编辑或更新惰性序列的单个元素最惯用的方法是什么?
没有用于修改序列/列表的单个元素的内置函数,但map-indexed 可能是最接近的东西。这不是列表的有效操作。假设你不需要需要懒惰,我会将序列倒入一个向量中,这就是mapv 所做的,即(into [] (map f coll))。根据您使用修改后序列的方式,对其进行矢量化和修改可能同样高效。
您可以使用map-indexed 编写一个函数来执行类似的懒惰操作:
(defn assoc-seq [s i v]
(map-indexed (fn [j x] (if (= i j) v x)) s))
或者,如果您想在不进行矢量化的情况下一次性完成这项工作,您也可以使用换能器:
(sequence
(comp
(map inc)
(map-indexed (fn [j x] (if (= 0 j) 666 x))))
[1 2 3])
实现您的用例是只修改惰性序列中的第一项,然后您可以在保持惰性的同时做一些更简单的事情:
(concat [666] (rest s))
更新回复:关于优化的评论:当更新 1,000,000 个元素的惰性序列中的第 500,000 个元素时,leetwinski 的 assoc-at 函数快了约 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
assoc-at 版本在更新大型惰性序列中的 first 项时快 2-3 倍,但不比 (last (concat [666] (rest big-lazy))) 快。