进入或vec:在Clojure中将序列转换回向量

时间:2012-08-20 19:51:04

标签: vector clojure sequence

我有以下代码,它增加了向量中每对的第一个元素:

(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更快。

所以我的问题是:

  1. 使用map优于矢量的正确方法是什么?
  2. 当我使用vecinto向量时,会发生什么?
  3. 相关但不重复的问题:

1 个答案:

答案 0 :(得分:27)

实际上,从Clojure 1.4.0开始,执行此操作的首选方法是使用mapv,类似于map,但其返回值是向量。它是迄今为止最有效的方法,根本没有不必要的中间分配。

Clojure 1.5.0将带来一个新的reducer库,它将为mapfiltertakedrop等提供通用方式,同时创建向量,可用与into []。您可以在1.5.0 alphas和最近的ClojureScript标记版本中使用它。

至于(vec some-seq)(into [] some-seq),第一个最终委托给一个将some-seq注入一个空瞬态向量的Java循环,而第二个用非常有效的Clojure代码做同样的事情。 。在这两种情况下,都需要进行一些初步检查,以确定在构造最终返回值时采用哪种方法。

对于小长度(最多32个)的Java数组,

vecinto []明显不同 - 第一个将对数组进行别名(将其用作新创建的向量的尾部)和要求随后不修改数组,以免向量内容发生变化(参见docstring);后者创建一个带有新尾部的新向量,而不关心将来对阵列的更改。