为什么clojure有这么多的地图构build函数?

新手的问题,但我真的不明白为什么有这么多的操作来构build地图clojure。

你有连接,联合和merge ,但他们似乎或多或less做同样的事情?

 (assoc {:a 1 :b 2} :c 3) (conj {:a 1 :b 2} {:c 3}) (merge {:a 1 :b 2} {:c 3}) 

什么是真正的差异,为什么所有这些方法所需要的时候或多或less都是一样的东西?

对于其他数据结构, assocconj行为非常不同:

 user=> (assoc [1 2 3 4] 1 5) [1 5 3 4] user=> (conj [1 2 3 4] 1 5) [1 2 3 4 1 5] 

如果你正在编写一个可以处理多种集合的函数,那么你的select将会产生很大的变化。

merge视为仅限地图的函数(对于其他集合类似于conj )。

我的想法:

  • 当你改变现有的键/值对时使用assoc – use
  • 当您添加新的键/值对时使用连接
  • 合并 – 在组合两个或更多地图时使用

实际上,这些function在与地图一起使用时performance得非常不同。

  1. conj

    首先,来自问题文本的(conj {:a 1 :b 2} :c 3)例子根本不起作用(1.1和1.2都没有; IllegalArgumentException被抛出)。 只有less数types可以映射到地图上,即两元素向量, clojure.lang.MapEntry (基本上相当于二元向量)和地图。

    请注意,地图的seq包含一堆MapEntry 。 因此你可以做例如

     (into a-map (filter a-predicate another-map)) 

    (注意,在可能的情况下使用conjconj! )。 merge也不允许你这样做。

  2. merge

    这几乎完全等同于conj ,但是它用空的哈希映射replace了它的nil参数 – 因此当链中的第一个“映射”碰巧是nil将返回一个映射。

     (apply conj [nil {:a 1} {:b 2}]) ; => ({:b 2} {:a 1}) ; clojure.lang.PersistentList (apply merge [nil {:a 1} {:b 2}]) ; => {:a 1 :b 2} ; clojure.lang.PersistentArrayMap 

    注意没有什么(除了docstring …)停止程序员使用与其他集合types的merge 。 如果这样做的话,就会出现怪异现象。 不build议。

  3. assoc

    同样,问题文本 – (assoc {:a 1 :b 2} {:c 3}) – 的(assoc {:a 1 :b 2} {:c 3})将不起作用; 相反,它会抛出一个IllegalArgumentExceptionassoc需要一个map参数,然后是偶数个参数 – 奇数位置(假设地图在位置0)是键,偶数位置是值。 我发现我比assoc东西更频繁地与地图联系conj ,尽pipe当我连接时,联系会感到麻烦。 😉

  4. merge-with

    为了完整起见,这是处理地图的最后一个基本function。 我觉得它非常有用。 它按照文档string的说明工作。 这里是一个例子:

     (merge-with + {:a 1} {:a 3} {:a 5}) ; => {:a 9} 

    请注意,如果一个地图包含一个“新的”键,它没有出现在任何左边的地图中,那么合并function将不会被调用。 这有时令人沮丧,但在1.2版本中,聪明的reify可以提供一个非零的“默认值”。

由于地图在Clojure中是一个无处不在的数据结构,因此有多种工具可以操作它们。 在不同的情况下,各种不同的function在语法上都是方便的。

我个人承担你提到的具体function:

  • 我用assoc来给给定一个键和值的地图添加一个值
  • 我使用合并来合并两个地图或一次添加多个新条目
  • 我一般不会使用连接图,因为我把它与精神上的列表联系起来