是否可以map
收藏而不将其转化为列表?我知道有关矢量的mapv
,但是关于集合或地图呢。是否有一个通用的map
函数将每个集合视为一个函子(即可映射的东西)并在映射后保留其类型?
以下是我的想法与现在发生的事情:
(map inc [1 2 3]) ; => [2 3 4], instead I get: (2 3 4)
(map inc #{1 2 3}) ; => #{3 2 4}, instead I get: (3 2 4)
(map inc {:a 1 :b 2 :c 3} ; => {:a 2 :b 3 :c 4}, instead I get: ClassCastException
答案 0 :(得分:9)
您的功能的返回值并不完全列出,只是在打印时它们在REPL中的表示方式。它们实际上是clojure.lang.LazySeq
的实例,您可以在此处看到:
(class (map inc [1 2 3]))
=> clojure.lang.LazySeq
而不是mappable
,Clojure试图将所有集合处理为Sequable
。 Seq
抽象允许将许多变换组合成一个集合上的操作流水线,其中维护原始输入类型通常没有意义,特别是在性能(速度)方面。在这种情况下,Clojure的动态特性实际上非常有用。
将操作输出转换为您想要的集合类型是微不足道的:
(-> (map inc [1 2 3])
(vec))
或更简单地说,使用into
:
(into [] (map inc [1 2 3]))
into
可用于列表,地图和集合:
(into #{} (map inc #{1 2 3}))
=> #{4 3 2}
在您尝试映射Hashmap的示例中,map
以clojure.lang.MapEntry
的形式传递一系列键值对,因此inc
需要一个数字,不能直接处理它。
你可以做这样的事情,使用 destructuring 来取出键和值:
(into {} (for [[k v] {:a 1 :b 2 :c 3}]
[k (inc v)]))
答案 1 :(得分:0)
into
函数将任何序列转换为特定类型。要保留原始类型,请将(empty data)
作为第一个参数传递:
(def data #{1 2 3})
(into (empty data) (map inc data))
;; #{4 3 2}