mru*_*cci 3 list clojure lazy-sequences
如果我有一个向量(def v [1 2 3]),我可以用 替换第一个元素(assoc v 0 666),获得[666 2 3]
但是,如果我在对向量进行映射后尝试做同样的事情:
(def v (map inc [1 2 3]))
(assoc v 0 666)
Run Code Online (Sandbox Code Playgroud)
抛出以下异常:
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.Associative
Run Code Online (Sandbox Code Playgroud)
编辑或更新惰性序列的单个元素的最惯用的方法是什么?
我应该map-indexed只使用和更改索引 0 还是将惰性序列实现为向量,然后通过关联/更新对其进行编辑?第一个具有保持懒惰的优点,而第二个效率较低但可能更明显。
我想对于第一个元素,我也可以使用 drop 和 cons。还有其他方法吗?我无法在任何地方找到任何示例。
编辑或更新惰性序列的单个元素的最惯用的方法是什么?
没有用于修改序列/列表的单个元素的内置函数,但map-indexed可能是最接近的。这不是列表的有效操作。假设您不需要懒惰,我会将序列倒入一个向量中,这就是mapvie 的作用(into [] (map f coll))。根据您使用修改后的序列的方式,对其进行矢量化和修改可能同样高效。
你可以写一个函数map-indexed来做一些类似和懒惰的事情:
(defn assoc-seq [s i v]
(map-indexed (fn [j x] (if (= i j) v x)) s))
Run Code Online (Sandbox Code Playgroud)
或者,如果您想在不进行矢量化的情况下一次性完成这项工作,您也可以使用转换器:
(sequence
(comp
(map inc)
(map-indexed (fn [j x] (if (= 0 j) 666 x))))
[1 2 3])
Run Code Online (Sandbox Code Playgroud)
意识到您的用例是只修改惰性序列中的第一项,然后您可以在保持惰性的同时做一些更简单的事情:
(concat [666] (rest s))
Run Code Online (Sandbox Code Playgroud)
更新:关于优化的评论:assoc-at在更新 1,000,000 个元素懒惰序列中的第 500,000 个元素时,leetwinski 的函数快了约 8 毫秒,因此,如果您希望从固有的低效操作中挤出每一点性能,则应该使用他的回答:
(def big-lazy (range 1e6))
(crit/bench
(last (assoc-at big-lazy 500000 666)))
Evaluation count : 1080 in 60 samples of 18 calls.
Execution time mean : 51.567317 ms
Execution time std-deviation : 4.947684 ms
Execution time lower quantile : 47.038877 ms ( 2.5%)
Execution time upper quantile : 65.604790 ms (97.5%)
Overhead used : 1.662189 ns
Found 6 outliers in 60 samples (10.0000 %)
low-severe 4 (6.6667 %)
low-mild 2 (3.3333 %)
Variance from outliers : 68.6139 % Variance is severely inflated by outliers
=> nil
(crit/bench
(last (assoc-seq big-lazy 500000 666)))
Evaluation count : 1140 in 60 samples of 19 calls.
Execution time mean : 59.553335 ms
Execution time std-deviation : 4.507430 ms
Execution time lower quantile : 54.450115 ms ( 2.5%)
Execution time upper quantile : 69.288104 ms (97.5%)
Overhead used : 1.662189 ns
Found 4 outliers in 60 samples (6.6667 %)
low-severe 4 (6.6667 %)
Variance from outliers : 56.7865 % Variance is severely inflated by outliers
=> nil
Run Code Online (Sandbox Code Playgroud)
assoc-at在更新大型惰性序列中的第一个项目时,该版本快 2-3 倍,但不比(last (concat [666] (rest big-lazy))).