2024 Clojure现状调查!中分享您的想法。

欢迎!请参阅关于页面以了解更多关于该功能的信息。

+5
序列

是否存在某个现有的核心函数,可以用它对一个已排序的列表进行分区,以便将[1 2 3 7 8 14 15 16 17 20 21 22]变为[[1 2 3] [7 8] [14 15 16 17] [20 21 22]]?

我想过如何用循环来实现(每次当当前值与前一个值的差大于1时开始一个新的列表),但我怀疑是否存在一种功能化的表达方式。

为了便于理解,这个问题是数据清洗练习的一个简化版本,我试图通过检查数据时间戳的差异来识别传感器数据的收集中断(例如,断电)。我可以看到像split-with这样的函数,但是我不认为提供给这些函数的谓词可以提供序列中前一个项的值,以便对序列中的项进行比较。

感谢您的考虑:)

2 答案

+4

已选中
 
最佳答案

据我所知,没有这样的partition-when,它会在谓词返回true时进行分区,这在您的案例中是需要的。
我建议使用reduce作为高级功能处理和低级循环之间的中间级别——从某种意义上说,处理是绑定到coll中的元素数量的,这使得它更简单。

(reduce
  (fn [acc n]
    (let [prev (peek (peek acc))]
      (if (and prev (= -1 (- prev n)))
        (update acc (dec (count acc)) conj n)
        (conj acc [n]))))
  []
  [1 2 3 7 8 14 15 16 17 20 21 22])
谢谢,我想我还不太习惯使用reduce来构建集合,但回顾一下,reduce确实是处理这类问题的基本工具,而不必降到循环层面。

库dev.weavejester/medley(“一个包含一些有用、大多数情况下看起来不突出在clojure.core命名空间的纯函数的小集合”)从1.7.0版本开始包含partition-between函数,这个函数可以用来对一个有序列表进行分区。

(require '[medley.core :refer [partition-between]])

(partition-between (fn [x y] (> y (inc x))) [1 2 3 7 8 14 15 16 17 20 21 22])
;; => ((1 2 3) (7 8) (14 15 16 17) (20 21 22))
...