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 作为中间层——从某种程度上说,这种方法更简单,因为处理过程被绑定到你集合中的元素数量。

(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])
by
谢谢,我想我还没有习惯使用 reduce 来构建集合,但回想起来,把 reduce 当作这种类型问题的基本工具是很合理的,而不需要降级到循环。
+2
by

自1.7.0以来,库 dev.weavejester/medley (“一组可能在 clojure.core 命名空间中看起来并不突兀的有用、纯函数”)包含了 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))
...