我有以下代码,它增加了向量中每对的第一个元素:
(vec (map (fn [[key value]] [(inc key) value]) [[0 :a] [1 :b]]))
但是我担心这段代码不够优雅,因为它首先使用map创建一个序列,然后将其强制转换为矢量。
考虑这个类比:
(into [] (map (fn [[key value]] [(inc key) value]) [[0 :a] [1 :b]]))
在#clojure@irc.freenode.net上有人告诉我,使用上面的代码是不好的,因为into
扩展为(reduce conj [] (map-indexed ...))
,这会在流程中产生许多中间对象。然后我被告知实际上into
不会扩展到(reduce conj ...)
并且在可能的情况下使用瞬态。同时测量经过的时间表明into
实际上比vec
更快。
所以我的问题是:
map
优于矢量的正确方法是什么?vec
和into
向量时,会发生什么?相关但不重复的问题:
答案 0 :(得分:27)
实际上,从Clojure 1.4.0开始,执行此操作的首选方法是使用mapv
,类似于map
,但其返回值是向量。它是迄今为止最有效的方法,根本没有不必要的中间分配。
Clojure 1.5.0将带来一个新的reducer库,它将为map
,filter
,take
,drop
等提供通用方式,同时创建向量,可用与into []
。您可以在1.5.0 alphas和最近的ClojureScript标记版本中使用它。
至于(vec some-seq)
和(into [] some-seq)
,第一个最终委托给一个将some-seq
注入一个空瞬态向量的Java循环,而第二个用非常有效的Clojure代码做同样的事情。 。在这两种情况下,都需要进行一些初步检查,以确定在构造最终返回值时采用哪种方法。
vec
和into []
明显不同 - 第一个将对数组进行别名(将其用作新创建的向量的尾部)和要求随后不修改数组,以免向量内容发生变化(参见docstring);后者创建一个带有新尾部的新向量,而不关心将来对阵列的更改。