映射集合而不将它们转换为列表

Tom*_*Tom 4 generics collections clojure

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
Run Code Online (Sandbox Code Playgroud)

Sco*_*ott 9

函数的返回值不是精确列表,而是打印时它们在REPL中的表示方式.clojure.lang.LazySeq正如您在此处所看到的,它们实际上是实例:

(class (map inc [1 2 3]))
=> clojure.lang.LazySeq
Run Code Online (Sandbox Code Playgroud)

而不是存在mappable,Clojure试图处理所有集合Sequable.该Seq抽象允许许多转换被组合在一起成为一个集合,其中保持了原有的输入类型往往是没有意义的,特别是在性能(速度)方面的操作管道.在这种情况下,Clojure的动态特性实际上非常有用.

将操作的输出转换为您想要的集合类型是微不足道的:

(-> (map inc [1 2 3])
    (vec))
Run Code Online (Sandbox Code Playgroud)

或者更简单地说,使用into:

(into [] (map inc [1 2 3]))
Run Code Online (Sandbox Code Playgroud)

into 可用于列表,地图和集合:

(into #{} (map inc #{1 2 3}))
=> #{4 3 2}
Run Code Online (Sandbox Code Playgroud)

在您尝试映射Hashmap的示例中,以a的形式map传递一系列键值对clojure.lang.MapEntry,因此inc需要一个数字,不能直接对其进行操作.

你可以做这样的事情,使用解构来拉出键和值:

(into {} (for [[k v] {:a 1 :b 2 :c 3}]
           [k (inc v)]))
Run Code Online (Sandbox Code Playgroud)