我一直遇到需要通过某个函数过滤一组地图的情况,然后从每个结果地图中提取一个值以进行最终的收集。
我经常使用这个基本结构:
(map :key (filter some-predicate coll))
我发现这基本上完成了与for循环相同的事情:
(for [x coll :when (some-predicate x)] (:key x))
一种方式比另一种更有效吗?我认为for
版本会更有效率,因为我们只进行一次收集..这是否准确?
答案 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))
虽然这基本上归结为个人风格