新手問題,但我真的不明白爲什麼有這麼多的操作構建地圖clojure。clojure爲什麼有這麼多的地圖構建函數?
你有conj
,assoc
和merge
,但他們似乎或多或少做同樣的事情?
(assoc {:a 1 :b 2} :c 3)
(conj {:a 1 :b 2} {:c 3})
(merge {:a 1 :b 2} {:c 3})
真的有什麼區別,爲什麼所有這些方法都需要它們做更多或更少的相同的事情?
新手問題,但我真的不明白爲什麼有這麼多的操作構建地圖clojure。clojure爲什麼有這麼多的地圖構建函數?
你有conj
,assoc
和merge
,但他們似乎或多或少做同樣的事情?
(assoc {:a 1 :b 2} :c 3)
(conj {:a 1 :b 2} {:c 3})
(merge {:a 1 :b 2} {:c 3})
真的有什麼區別,爲什麼所有這些方法都需要它們做更多或更少的相同的事情?
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]
如果你正在編寫一個可處理多種類型的集合的功能,那麼你的選擇將有很大的不同。
將merge
視爲僅限地圖功能(其類似於其他集合的conj
)。
我的看法:
由於地圖在Clojure中是一個無處不在的數據結構,因此擁有多個工具來處理它們是很有意義的。在稍有不同的情況下,各種不同的功能在語法上都是方便的。
我個人拿上你提到的具體功能:
我認爲慣用的方法將是使用的任何功能,其中所加入的新項目的格式匹配到地圖最初變得可用;如果它是地圖,使用'merge',如果作爲一組鍵和值不集合在一個集合中,使用'assoc'等。我真正想要指出的是,'conj'是* universal * Clojure數據結構構建函數 - 你不能真正將它保存在列表抽屜中。 – 2010-07-08 17:46:45
@Michal也許你是對的 - 但由於某種原因,我對函數不信任,它們在不同的輸入類型上進行語義上非常不同的事情,而沒有警告:-) – mikera 2010-07-08 19:31:19
我會爭辯說,'conj' **在語義上等同於操作在不同的輸入類型。 ;) – dbyrne 2010-07-08 19:59:39
實際上,這些函數在與地圖一起使用時表現得非常不同。
conj
:
首先,從問題文本(conj {:a 1 :b 2} :c 3)
例子並不在所有的工作(既不與1.1也不與1.2; IllegalArgumentException
拋出)。在地圖上只有少數幾種類型,即兩元素矢量,clojure.lang.MapEntry
(它們基本上相當於二元矢量)和地圖。
請注意,地圖的seq
包含一堆MapEntry
s。因此你可以做例如
(into a-map (filter a-predicate another-map))
(注意:into
使用conj
- 或conj!
,如果可能的話 - 內部)。 merge
和assoc
都不允許你這樣做。
merge
:
這幾乎完全等同於conj
,但它取代了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
注意沒有什麼(除了文檔字符串...),從使用merge
與其他集合類型停止程序員。如果有人那樣做,就會出現怪異現象;不建議。
assoc
:
再次,從試題內容的例子 - (assoc {:a 1 :b 2} {:c 3})
- 將無法正常工作;相反,它會拋出IllegalArgumentException
。 assoc
需要一個映射參數,然後是偶數個參數 - 奇數位置(假設地圖位於位置0)是鍵,偶數位置是值。我發現我的assoc
東西地圖更經常比我conj
,雖然當我conj
,assoc
會感到麻煩。 ;-)
merge-with
:
爲了完整起見,這是處理地圖最終的基本功能。我覺得它非常有用。它按照文檔字符串的說明工作。這裏有一個例子:
(merge-with + {:a 1} {:a 3} {:a 5})
; => {:a 9}
注意,如果地圖中包含一個「新」鍵,未在任何地圖,它的左側的發生,合併功能將不會被調用。這偶爾會令人沮喪,但在1.2中,巧妙的reify
可以提供非nil
「默認值」的地圖。
爲了說明最後一點'merge-with',我準備了以下Gist:http://gist.github.com/468332 – 2010-07-08 17:28:22
感謝您的解釋。正如你看到的,我有一個打字錯誤,並轉換了conj和assoc之間的第二個參數。 – grm 2010-07-08 22:02:16
還有'(進入{:1:B 2} {:C 3})' – VitoshKa 2014-03-22 03:50:53