【问题标题】:Into or vec: converting sequence back to vector in ClojureInto or vec:在 Clojure 中将序列转换回向量
【发布时间】:2023-03-31 13:05:02
【问题描述】:

我有以下代码递增向量中每对的第一个元素:

(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 与向量一起使用时,下面会发生什么?

相关但不重复的问题:

【问题讨论】:

    标签: vector clojure sequence


    【解决方案1】:

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

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

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

    vecinto [] 对于小长度(最多 32 个)的 Java 数组有很大不同——第一个将为数组起别名(将其用作新创建的向量的尾部)并要求数组不随后进行修改,以免向量的内容发生变化(参见文档字符串);后者创建一个带有新尾部的新向量,并且不关心数组的未来变化。

    【讨论】:

    • 谢谢。 (mapv f args)(into (vector) (map f args)) 简洁得多
    • 这个答案仍然是真实的吗?我最感兴趣的是 ClojureScript。谢谢
    • mapv 仍然存在,如果您想在向量中累积跨可序列集合映射函数的结果,这是最好的方法。 Reducers 也仍然存在,但是 Clojure 现在有转换器,它们非常适合使用更多涉及的转换来构建向量和其他集合 - (into [] (map inc) input-coll) 等。如果您可以通过 clojure.core.reducers/fold 从并行化中受益,Reducers 仍然是最佳选择,但这是与 ClojureScript 无关。
    • 这仍然适用于vec 和“小数组”吗?我做了以下实验:``` (def my-a (int-array [1 2 3])) (def my-v (vec my-a)) my-v ;=> [1 2 3] (aset my -a 1 10)) (java.util.Arrays/toString my-a) ;=> "[1, 10, 3]" ;=> my-v [1 2 3] ```
    • @JurajMartinka 确实如此,但仅适用于Object 的数组。你的是一个原始数组,所以当你在它上面调用vec 时,它的所有项都会被装箱并复制到一个相同长度的新对象数组中。这是因为由vecvector 返回并由文字语法[…] 创建的持久向量始终存储对象引用。内置了一个独特的向量类型,可以保存原始项目,请参阅clojure.core/vector-of;注意。目前使用它通常需要对访问进行装箱,因此应该仔细评估它是否合适,即使使用原语也不默认它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多