这是有意义的:
user=> (into {} [[:a 1] [:b 2]])
{:a 1, :b 2}但是为什么这会产生一个错误呢?
user=> (into {} (partition 2 [:a 1 :b 2]))
ClassCastException clojure.lang.Keyword cannot be cast to java.util.Map$Entry clojure.lang.ATransientMap.conj (ATransientMap.java:44)只是为了确认一下:
user=> (partition 2 [:a 1 :b 2])
((:a 1) (:b 2))into对惰性序列有问题吗?如果有,原因何在?
除了解释这种方法不起作用的原因之外,推荐的将像[:a 1 :b 2]这样的键-值对序列组合到映射中的方法是什么?(apply conj似乎也不起作用。)
发布于 2018-01-27 11:59:27
您可以将序列apply到assoc
(apply assoc {:foo 1} [:a 1 :b 2])
=> {:foo 1, :a 1, :b 2}在懒惰序列方面有问题吗?如果有,原因何在?
不,into通常用于延迟评估的序列。这是惰性的,但每个键/值元组都是一个向量,这就是为什么当into减少映射中的对时,它会起作用:
(into {} (map vector (range 3) (repeat :x)))
=> {0 :x, 1 :x, 2 :x}这不起作用,因为键/值对是列表:
(into {} (map list (range 3) (repeat :x)))所以区别不是懒惰;这是因为into在地图上使用reduce和conj,这只适用于向量键/值对(或MapEntry):
(conj {} [:a 1]) ;; ok
(conj {} (MapEntry. :a 1)) ;; ok
(conj {} '(:a 1)) ;; not ok更新:assoc包装器,用于应用评论中建议的空/nil序列:
(defn assoc*
([m] m)
([m k v & kvs]
(apply assoc m k v kvs)))发布于 2018-01-27 12:05:25
推荐的方式-(假设seq arg是非空的,正如OP所指出的)-将是
Clojure 1.9.0
user=> (apply assoc {} [:a 1 :b 2])
{:a 1, :b 2}带有partition的版本不起作用,因为partition返回的块是seqs,并且当conj'd以矢量和实际映射条目的方式添加到映射时,这些块不会被视为映射条目。
例如,(into {} (map vec) (partition 2 [:a 1 :b 2]))可以工作,因为这里在conjing之前将对转换为向量。
尽管如此,除非有一些特定的环境使得into很方便(例如,如果您有一堆传感器,希望用来预处理您的partition-generated对等),否则使用assoc的方法是更可取的。
发布于 2018-01-28 07:18:38
Clojure将诸如[:a 1]之类的2-vec视为等同于MapEntry,执行等同于“自动类型转换”的操作。我尽量避免这一点,而且总是很明确。
(first {:a 1}) => <#clojure.lang.MapEntry [:a 1]>
(conj {:a 1} [:b 2]) => <#clojure.lang.PersistentArrayMap {:a 1, :b 2}>因此我们可以看到,MapEntry打印方式类似于向量,但具有不同的类型(就像Clojure seq打印方式类似于list,但具有不同的类型)。seq将Clojure map转换为一系列的MapEntry,而first会得到第一个(大多数Clojure函数在任何其他处理之前都会在任何输入集合上调用(seq ...) )。
请注意,conj执行反向类型转换,将向量 [:b 2]视为MapEntry。但是,conj不会为list或seq执行自动类型转换
(throws? (conj {:a 1} '(:b 2)))
(throws? (into {:a 1} '(:b 2)))into在since it is basically just (reduce conj <1st-arg> <2nd-seq>)中也有同样的问题。
其他答案已经有了3种工作方式:
(assoc {} :b 2) => {:b 2}
(conj {} [:b 2]) => {:b 2}
(into {} [[:a 1] [:b 2]]) => {:a 1, :b 2}然而,我会避免这些,并坚持使用hash-map或sorted-map,这两种方法都避免了输入序列为空的问题:
(apply hash-map []) => {} ; works for empty input seq
(apply hash-map [:a 1 :b 2]) => {:b 2, :a 1}如果您的输入序列是一个配对列表,flatten有时会很有帮助:
(apply sorted-map (flatten [[:a 1] [:b 2]])) => {:a 1, :b 2}
(apply hash-map (flatten '((:a 1) (:b 2)))) => {:a 1, :b 2}附注:
请注意,这些是不同的:
的形式列出
P.P.S
如果您已经有了一个映射,并且想要合并成一个(可能为空的)键值对序列,那么只需组合使用into和hash-map
(into {:a 1} (apply hash-map [])) => {:a 1}
(into {:a 1} (apply hash-map [:b 2])) => {:a 1, :b 2}https://stackoverflow.com/questions/48472425
复制相似问题