什么是编辑或更新惰性序列中单个元素的最惯用方式?
没有内置函数可以修改序列/列表中的单个元素,但是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
版本在更新大型惰性序列中的 第一个 项目时比原版本快2-3倍,但与 (last (concat [666] (rest big-lazy)))
一样快。