4

假设我有一个字符串集合,我想返回所有长度超过 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

所以:

  • 我们有很多东西
  • 我们想要返回一个有序的集合
  • 使用计算量大的函数的结果进行过滤和排序,每个事物只能调用一次

是否有执行此操作的现有功能,或者我需要构建自己的功能?

4

3 回答 3

8

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

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

如果计算所讨论的属性真的那么昂贵,那么分配向量的开销应该几乎消失了。

于 2013-08-13T06:12:52.200 回答
1

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

(time (dotimes [_ 1e5] ...))
于 2013-08-13T09:25:20.463 回答
0

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

(for [[c sv] (sort-by first (group-by count strings)) :when (> c 4) s sv] s)
于 2013-08-13T14:13:35.720 回答