你如何在Clojure中结合使用排序和过滤?

时间:2013-08-13 06:08:30

标签: clojure

假设我有一个字符串集合,我希望返回超过4个字符的所有字符串,首先按最短字符串排序。

你可以通过以下方式解决这个问题:

(def strings ["this" "is" "super" "cool" "everybody" "isn't" "clojure" "great!?!?"])
(sort-by count < (filter #(> (count %) 4) strings))
;; > ("super" "isn't" "clojure" "everybody" "great!?!?")

请注意,我们两次使用count。这可能在这里很好,但如果count不是count怎么办?如果我们调用count而不是super-expensive-function而不是绝对必要的话,那么我们真的不会运行超过{{1}}而不是什么呢?

所以:

  • 我们收藏了一些东西
  • 我们希望返回有序的收藏品
  • 使用计算成本高昂的函数的结果进行过滤和排序,每个事物只能调用一次

是否存在执行此功能的现有功能,还是需要构建自己的功能?

3 个答案:

答案 0 :(得分:8)

最简单的解决方案是将每个项目与其昂贵的计算属性配对,然后过滤和排序,然后丢弃参数:

(->> strings
     (map (juxt identity count))
     (filter (fn [[_ c]] (> c 4)))
     (sort-by peek)
     (map first))

如果计算有问题的属性确实非常昂贵,那么分配向量的开销几乎会消失。

答案 1 :(得分:1)

也许JIT编译器可以发现这个昂贵的中间结果可以在两个操作之间缓存?鉴于手动缓存结果的复杂性增加,值得尝试排除这种可能性。对于各种时间测量解决方案,我会进行几次性能测试:

(time (dotimes [_ 1e5] ...))

答案 2 :(得分:0)

您可以使用group-by进行配对,并使用列表推导进行聚合和过滤。

(for [[c sv] (sort-by first (group-by count strings)) :when (> c 4) s sv] s)