说我有像
这样的clojure序列'(1 2 3 6 7 8)
我希望将其拆分,以便每当遇到可被3整除的元素时列表就会分裂,因此结果看起来像
'((1 2) (3) (6 7 8))
(编辑:我真正需要的是
[[1 2] [3] [6 7 8]]
,但我也会接受序列版本:)
在clojure中执行此操作的最佳方法是什么?
partition-by
没有帮助:
(partition-by #(= (rem % 3) 0) '(1 2 3 6 7 8))
; => ((1 2) (3 6) (7 8))
split-with
已关闭:
(split-with #(not (= (rem % 3) 0)) '(1 2 3 6 7 8))
; => [(1 2) (3 6 7 8)]
答案 0 :(得分:3)
这样的东西?
(defn partition-with
[f coll]
(lazy-seq
(when-let [s (seq coll)]
(let [run (cons (first s) (take-while (complement f) (next s)))]
(cons run (partition-with f (seq (drop (count run) s))))))))
(partition-with #(= (rem % 3) 0) [1 2 3 6 7 8 9 12 13 15 16 17 18])
=> ((1 2) (3) (6 7 8) (9) (12 13) (15 16 17) (18))
答案 1 :(得分:1)
还有一个旧学校基于减少的解决方案:
user> (defn split-all [pred items]
(when (seq items)
(apply conj (reduce (fn [[acc curr] x]
(if (pred x)
[(conj acc curr) [x]]
[acc (conj curr x)]))
[[] []] items))))
#'user/split-all
user> (split-all #(zero? (rem % 3)) '(1 2 3 6 7 8 10 11 12))
;;=> [[1 2] [3] [6 7 8 10 11] [12]]
答案 2 :(得分:0)
这是一个有趣的问题。我最近将a function split-using
添加到the Tupelo library,这似乎非常适合。我在下面的代码中保留了spyx
调试语句,以便您了解事情的进展情况:
(ns tst.clj.core
(:use clojure.test tupelo.test)
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(defn start-segment? [vals]
(zero? (rem (first vals) 3)))
(defn partition-using [pred vals-in]
(loop [vals vals-in
result []]
(if (empty? vals)
result
(t/spy-let [
out-first (take 1 vals)
[out-rest unprocessed] (split-using pred (spyx (next vals)))
out-vals (glue out-first out-rest)
new-result (append result out-vals)]
(recur unprocessed new-result)))))
这给我们的输出如下:
out-first => (1)
(next vals) => (2 3 6 7 8)
[out-rest unprocessed] => [[2] (3 6 7 8)]
out-vals => [1 2]
new-result => [[1 2]]
out-first => (3)
(next vals) => (6 7 8)
[out-rest unprocessed] => [[] [6 7 8]]
out-vals => [3]
new-result => [[1 2] [3]]
out-first => (6)
(next vals) => (7 8)
[out-rest unprocessed] => [[7 8] ()]
out-vals => [6 7 8]
new-result => [[1 2] [3] [6 7 8]]
(partition-using start-segment? [1 2 3 6 7 8]) => [[1 2] [3] [6 7 8]]
或更大的输入向量:
(partition-using start-segment? [1 2 3 6 7 8 9 12 13 15 16 17 18 18 18 3 4 5])
=> [[1 2] [3] [6 7 8] [9] [12 13] [15 16 17] [18] [18] [18] [3 4 5]]
您也可以使用嵌套loop/recur
创建解决方案,但已在split-using
函数中编码:
(defn split-using
"Splits a collection based on a predicate with a collection argument.
Finds the first index N such that (pred (drop N coll)) is true. Returns a length-2 vector
of [ (take N coll) (drop N coll) ]. If pred is never satisified, [ coll [] ] is returned."
[pred coll]
(loop [left []
right (vec coll)]
(if (or (empty? right) ; don't call pred if no more data
(pred right))
[left right]
(recur (append left (first right))
(rest right)))))
实际上,上述功能似乎将来会有用。 partition-using
has now been added到图珀洛图书馆。