请在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 作为处理这类问题的基本工具是很有道理的,无需降级到循环。
+2

库 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))
...