过滤,然后映射?或者只是使用for循环?

时间:2015-03-24 00:58:59

标签: clojure

我一直遇到需要通过某个函数过滤一组地图的情况,然后从每个结果地图中提取一个值以进行最终的收集。

我经常使用这个基本结构:

(map :key (filter some-predicate coll))

我发现这基本上完成了与for循环相同的事情:

(for [x coll :when (some-predicate x)] (:key x))

一种方式比另一种更有效吗?我认为for版本会更有效率,因为我们只进行一次收集..这是否准确?

1 个答案:

答案 0 :(得分:3)

两者都没有显着差异。

这两个都返回一个未实现的惰性序列,每次读取一个项目时都会计算它。第一个不会遍历列表两次,而是创建一个惰性序列,该序列生成与过滤器匹配的项目,然后由map函数立即消耗(仍然懒惰)。因此,在第一种情况下,您有一个懒惰的序列从懒惰的另一个懒惰序列中消耗项目。另一方面,对for的调用产生了一个lazy-seq,每一步都有很多逻辑。

您可以看到例如扩展到的代码:

(pprint (macroexpand-1 '(for [x coll :when (some-predicate x)] (:key x)))) 

总的来说,性能与第二种方法非常相似,可能产生的垃圾量略少,因此根据性能决定这些方法的唯一方法是进行基准测试。在样式的基础上,我选择第一个,因为它更短,但我可以选择用线程最后一个宏来编写它,如果有更多的阶段。

(->> coll
     (filter some-predicate)
     (take some-limit)
     (map :key))

虽然这基本上归结为个人风格