Clojure 过滤,然后映射?还是只使用for循环?

Clojure 过滤,然后映射?还是只使用for循环?,clojure,Clojure,我经常遇到这样的情况:我需要通过某个函数过滤贴图集合,然后从每个生成的贴图中提取一个值来生成最终的集合 我经常使用这种基本结构: (map :key (filter some-predicate coll)) 我突然想到,这基本上完成了与for循环相同的事情: (for [x coll :when (some-predicate x)] (:key x)) 一种方法比另一种更有效吗?我认为版本的会更有效,因为我们只会检查一次收集。。这准确吗?两者都没有显著差异 这两种方法都返回一个未实现的延

我经常遇到这样的情况:我需要通过某个函数过滤贴图集合,然后从每个生成的贴图中提取一个值来生成最终的集合

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

(map :key (filter some-predicate coll))
我突然想到,这基本上完成了与for循环相同的事情:

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

一种方法比另一种更有效吗?我认为版本的
会更有效,因为我们只会检查一次收集。。这准确吗?

两者都没有显著差异

这两种方法都返回一个未实现的延迟序列,在该序列中,每次读取一个项时都会计算该项。第一个不遍历列表两次,而是创建一个惰性序列,该序列生成与过滤器匹配的项,然后立即被map函数使用(仍然是惰性的)。因此,在第一种情况下,您有一个惰性序列惰性地消费另一个惰性序列中的项目。另一方面,对
调用会生成一个在每个步骤中都包含大量逻辑的惰性seq

您可以看到示例扩展为以下代码:

(pprint (macroexpand-1 '(for [x coll :when (some-predicate x)] (:key x)))) 
总的来说,性能将与第二种方法非常相似,可能产生的垃圾会稍微少一些,因此您根据性能在这两种方法之间做出决定的唯一方法将是基准测试。根据样式,我选择第一个,因为它较短,但如果有更多的阶段,我可能会选择使用thread last宏编写它

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

虽然这基本上归结为个人风格,
macroexpand-1
很有启发性。谢谢你的回答