更新矢量工作正常:
(update [{:idx :a} {:idx :b}] 1 (fn [_] {:idx "Hi"}))
;; => [{:idx :a} {:idx "Hi"}]
然而,尝试使用列表执行相同的操作不起作用:
(update '({:idx :a} {:idx :b}) 1 (fn [_] {:idx "Hi"}))
;; => ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Associative clojure.lang.RT.assoc (RT.java:807)
assoc
确实存在同样的问题。
我想对延迟类型而不是向量进行更新和覆盖操作。这里有什么根本问题,有没有办法解决它?
答案 0 :(得分:3)
根本问题是update
函数适用于关联结构,即向量和映射。列表不能将键作为查找值的函数。
user=> (associative? [])
true
user=> (associative? {})
true
user=> (associative? `())
false
update
在幕后使用get
进行随机访问工作。
我想对延迟类型执行更新和覆盖操作 而不是矢量
目前尚不清楚想要实现的目标。你是正确的,矢量不是懒惰的,但是如果你想对集合进行随机访问操作,那么矢量对于这种情况是理想的,而列表则不是。
有没有办法解决它?
是的,但您仍然无法使用update
功能,在您的情况下看起来不会有任何好处。
使用列表,您必须遍历列表才能访问列表中的某个索引 - 所以在许多情况下,即使它是懒惰的,您也必须实现大量的序列。
答案 1 :(得分:2)
您可以使用take
和drop
:
(defn lupdate [list n function]
(let [[head & tail] (drop n list)]
(concat (take n list)
(cons (function head) tail))))
user=> (lupdate '(a b c d e f g h) 4 str)
(a b c d "e" f g h)
使用延迟序列,这意味着您将计算n
个第一个值(但不会计算剩余的值,这毕竟是我们使用延迟序列的重要部分)。您还必须考虑空间和时间的复杂性(concat等)。但如果你真的需要对懒惰序列进行操作,那就是你要走的路。
答案 2 :(得分:1)
在你的问题背后找到你想要解决的问题:
您可以使用Clojure的序列函数构建一个简单的解决方案:
(defn elf [n]
(loop [population (range 1 (inc n))]
(if (<= (count population) 1)
(first population)
(let [survivors (->> population
(take-nth 2)
((if (-> population count odd?) rest identity)))]
(recur survivors)))))
例如,
(map (juxt identity elf) (range 1 8))
;([1 1] [2 1] [3 3] [4 1] [5 3] [6 5] [7 7])
这具有复杂性O(n)。您可以通过将人口计数作为循环中的冗余参数传递,或者将count
和population
转储到向量中来加快survivors
。序列函数 - take-nth
和rest
- 完全能够进行除草。
我希望我做对了!