我希望将seq"chunk"为subseqs,与partition-by相同,不同的是该函数不应用于每个单独的元素,而是应用于一系列元素.
所以,例如:
(gather (fn [a b] (> (- b a) 2))
[1 4 5 8 9 10 15 20 21])
Run Code Online (Sandbox Code Playgroud)
会导致:
[[1] [4 5] [8 9 10] [15] [20 21]]
Run Code Online (Sandbox Code Playgroud)
同样:
(defn f [a b] (> (- b a) 2))
(gather f [1 2 3 4]) ;; => [[1 2 3] [4]]
(gather f [1 2 3 4 5 6 7 8 9]) ;; => [[1 2 3] [4 5 6] [7 8 9]]
Run Code Online (Sandbox Code Playgroud)
我的想法是我将列表的开头和下一个元素应用于函数,如果函数返回true,我们将列表的当前头部分区分割到新的分区.
我写过:
(defn gather
[pred? lst]
(loop [acc [] cur [] l lst]
(let [a (first cur)
b (first l)
nxt (conj cur b)
rst (rest l)]
(cond
(empty? l) (conj acc cur)
(empty? cur) (recur acc nxt rst)
((complement pred?) a b) (recur acc nxt rst)
:else (recur (conj acc cur) [b] rst)))))
Run Code Online (Sandbox Code Playgroud)
它有效,但我知道有一种更简单的方法.我的问题是:
是否有内置函数来执行此操作,此功能是不必要的?如果没有,是否有一个我忽略的更惯用(或更简单)的解决方案?结合减少和吃东西的东西?
谢谢.
A. *_*ebb 11
我们(所有)似乎误解了你的问题,因为只要谓词持续连续元素,就想要开始一个新的分区.
另一个,懒惰,建立在 partition-by
(defn partition-between [pred? coll]
(let [switch (reductions not= true (map pred? coll (rest coll)))]
(map (partial map first) (partition-by second (map list coll switch)))))
Run Code Online (Sandbox Code Playgroud)
(partition-between (fn [a b] (> (- b a) 2)) [1 4 5 8 9 10 15 20 21])
;=> ((1) (4 5) (8 9 10) (15) (20 21))
Run Code Online (Sandbox Code Playgroud)
实际问题要求我们在pred?保持当前分区和当前元素的开头时启动新分区.为此,我们可以partition-by通过一些调整来解决它的来源.
(defn gather [pred? coll]
(lazy-seq
(when-let [s (seq coll)]
(let [fst (first s)
run (cons fst (take-while #((complement pred?) fst %) (next s)))]
(cons run (gather pred? (seq (drop (count run) s))))))))
Run Code Online (Sandbox Code Playgroud)
(gather (fn [a b] (> (- b a) 2)) [1 4 5 8 9 10 15 20 21])
;=> ((1) (4 5) (8 9 10) (15) (20 21))
(gather (fn [a b] (> (- b a) 2)) [1 2 3 4])
;=> ((1 2 3) (4))
(gather (fn [a b] (> (- b a) 2)) [1 2 3 4 5 6 7 8 9])
;=> ((1 2 3) (4 5 6) (7 8 9))
Run Code Online (Sandbox Code Playgroud)