为什么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都是一样的东西?
对于其他数据结构, assoc
和conj
行为非常不同:
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得非常不同。
-
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))
(注意,在可能的情况下使用
conj
或conj!
)。merge
也不允许你这样做。 -
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议。 -
assoc
:同样,问题文本 –
(assoc {:a 1 :b 2} {:c 3})
– 的(assoc {:a 1 :b 2} {:c 3})
将不起作用; 相反,它会抛出一个IllegalArgumentException
。assoc
需要一个map参数,然后是偶数个参数 – 奇数位置(假设地图在位置0)是键,偶数位置是值。 我发现我比assoc
东西更频繁地与地图联系conj
,尽pipe当我连接时,联系会感到麻烦。 😉 -
merge-with
:为了完整起见,这是处理地图的最后一个基本function。 我觉得它非常有用。 它按照文档string的说明工作。 这里是一个例子:
(merge-with + {:a 1} {:a 3} {:a 5}) ; => {:a 9}
请注意,如果一个地图包含一个“新的”键,它没有出现在任何左边的地图中,那么合并function将不会被调用。 这有时令人沮丧,但在1.2版本中,聪明的
reify
可以提供一个非零的“默认值”。
由于地图在Clojure中是一个无处不在的数据结构,因此有多种工具可以操作它们。 在不同的情况下,各种不同的function在语法上都是方便的。
我个人承担你提到的具体function:
- 我用assoc来给给定一个键和值的地图添加一个值
- 我使用合并来合并两个地图或一次添加多个新条目
- 我一般不会使用连接图,因为我把它与精神上的列表联系起来