我不断遇到这样的情况:我需要通过某种函数过滤一组 map ,然后从每个结果 map 中提取一个值以形成最终的集合。
我经常使用这个基本结构:
(map :key (filter some-predicate coll))
我发现这基本上完成了与 for 循环相同的事情:
(for [x coll :when (some-predicate x)] (:key x))
一种方法比另一种方法更有效吗?我认为 for
版本会更有效,因为我们只遍历集合一次。这准确吗?
最佳答案
两者都没有显着差异。
这两者都返回一个未实现的惰性序列,每次读取一个项目时都会计算它。第一个不会遍历列表两次,而是创建一个惰性序列,该序列生成与过滤器匹配的项目,然后立即由映射函数使用(仍然是惰性的)。因此,在第一种情况下,您有一个惰性序列惰性地消耗另一个惰性序列中的项目。另一方面,对 for
的调用会生成一个在每个步骤中包含大量逻辑的惰性序列。
您可以看到示例扩展为的代码:
(pprint (macroexpand-1 '(for [x coll :when (some-predicate x)] (:key x))))
总体而言,性能与第二种方法非常相似,可能产生的垃圾稍微少一些,因此您根据性能在这些方法之间做出决定的唯一方法是基准测试。根据风格,我选择第一个,因为它更短,但如果有更多阶段,我可能会选择使用 thread-last 宏来编写它。
(->> coll
(filter some-predicate)
(take some-limit)
(map :key))
虽然这基本上取决于个人风格
关于clojure - 过滤,然后映射?或者只使用一个for循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29223193/