首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >闭包按过滤器划分

闭包按过滤器划分
EN

Stack Overflow用户
提问于 2011-04-14 14:32:59
回答 5查看 5.3K关注 0票数 15

在Scala中,分区方法将序列分成两个单独的序列--谓词为true的序列和为false的序列:

代码语言:javascript
复制
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函数将序列拆分为多个子序列,每个子序列是执行或不满足谓词的最长子集:

代码语言:javascript
复制
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生成:

代码语言:javascript
复制
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方法执行相同的操作?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-04-16 17:23:17

我相信你要找的函数是核心/小组-by。它将键映射返回到原始序列中的项目列表,分组函数将返回该键。如果您使用真/假生成谓词,您将得到您正在寻找的拆分。

代码语言:javascript
复制
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-byclojure.core而不是separate中。

票数 21
EN

Stack Overflow用户

发布于 2011-04-14 15:13:32

Clojure.contrib.seq-utils的一部分:

代码语言:javascript
复制
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)]                                                                                                                                   
票数 4
EN

Stack Overflow用户

发布于 2011-04-14 15:31:06

请注意,Jürgen、禤浩焯和Mikera的答案都经过了两次输入序列。

代码语言:javascript
复制
(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是可能的,但很难理解。事实上,我相信这比简单的第二关要慢。但我还没查过。

代码语言:javascript
复制
(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)]))

这是你所能得到的最懒惰的:

代码语言:javascript
复制
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

看到上面的情况,我会说“去渴望”或“去两次传球”。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5664833

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档