在Scala中,分区方法将序列分成两个单独的序列--谓词为true的序列和为false的序列:
scala> List(1, 5, 2, 4, 6, 3, 7, 9, 0, 8).partition(_ % 2 == 0)
res1: (List[Int], List[Int]) = (List(2, 4, 6, 0, 8),List(1, 5, 3, 7, 9))注意,Scala实现只遍历序列一次。
在Clojure中,partition-by函数将序列拆分为多个子序列,每个子序列是执行或不满足谓词的最长子集:
user=> (partition-by #(= 0 (rem % 2)) [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
((1 5) (2 4 6) (3 7 9) (0 8))当split-by生成:
user=> (split-with #(= 0 (rem % 2)) [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
[() (1 5 2 4 6 3 7 9 0 8)]是否有一个内置的Clojure函数与Scala partition方法执行相同的操作?
发布于 2011-04-16 17:23:17
我相信你要找的函数是核心/小组-by。它将键映射返回到原始序列中的项目列表,分组函数将返回该键。如果您使用真/假生成谓词,您将得到您正在寻找的拆分。
user=> (group-by even? [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
{false [1 5 3 7 9], true [2 4 6 0 8]}如果您查看实施,它满足了您的要求,即它只使用一次传递。另外,它在引擎盖下使用瞬变,因此它应该比迄今为止发布的其他解决方案更快。一个警告是,您应该确保您的分组函数生成的键。如果它生成nil而不是false,那么您的地图将在nil键下列出失败项。如果您的分组函数生成非零值而不是true,则可以在多个键下列出传递值。不是什么大问题,只是要注意,您需要为您的分组函数使用一个真/假生成谓词。
group-by的好处在于,它比将序列拆分为传递项和失败项更为普遍。您可以很容易地使用这个函数将您的序列分组到您需要的多个类别中。非常有用和灵活。这可能就是为什么group-by在clojure.core而不是separate中。
发布于 2011-04-14 15:13:32
Clojure.contrib.seq-utils的一部分:
user> (use '[clojure.contrib.seq-utils :only [separate]])
nil
user> (separate even? [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
[(2 4 6 0 8) (1 5 3 7 9)] 发布于 2011-04-14 15:31:06
请注意,Jürgen、禤浩焯和Mikera的答案都经过了两次输入序列。
(defn single-pass-separate
[pred coll]
(reduce (fn [[yes no] item]
(if (pred item)
[(conj yes item) no]
[yes (conj no item)]))
[[] []]
coll))一次传球只能是一种渴望。懒惰必须是两次传球,再加上软弱无力地抱住头。
编辑:lazy-single-pass-separate是可能的,但很难理解。事实上,我相信这比简单的第二关要慢。但我还没查过。
(defn lazy-single-pass-separate
[pred coll]
(let [coll (atom coll)
yes (atom clojure.lang.PersistentQueue/EMPTY)
no (atom clojure.lang.PersistentQueue/EMPTY)
fill-queue (fn [q]
(while (zero? (count @q))
(locking coll
(when (zero? (count @q))
(when-let [s (seq @coll)]
(let [fst (first s)]
(if (pred fst)
(swap! yes conj fst)
(swap! no conj fst))
(swap! coll rest)))))))
queue (fn queue [q]
(lazy-seq
(fill-queue q)
(when (pos? (count @q))
(let [item (peek @q)]
(swap! q pop)
(cons item (queue q))))))]
[(queue yes) (queue no)]))这是你所能得到的最懒惰的:
user=> (let [[y n] (lazy-single-pass-separate even? (report-seq))] (def yes y) (def no n))
#'user/no
user=> (first yes)
">0<"
0
user=> (second no)
">1<"
">2<"
">3<"
3
user=> (second yes)
2看到上面的情况,我会说“去渴望”或“去两次传球”。
https://stackoverflow.com/questions/5664833
复制相似问题