[英]The unexpected selection and merging behavior of clojure.set/join
我想用某些特定值覆蓋關系中的某些默認值,並偶然發現了一些我不太了解的行為。
(clojure.set/join
#{
{:a 1 :b nil :c "2"}
{:a 2 :b "2" :c nil}
{:a 3 :b 1 :c 5}
}
#{
{:a 1 :b 44}
{:a 3 :b 11 :c 55}
}
{:a :a})
解析為#{{:a 3, :c 5, :b 1} {:c "2", :a 1, :b nil}}
。
如果翻轉參數,我將得到相同的結果。
(clojure.set/join
#{
{:a 1 :b 44}
{:a 3 :b 11 :c 55}
}
#{
{:a 1 :b nil :c "2"}
{:a 2 :b "2" :c nil}
{:a 3 :b 1 :c 5}
}
{:a :a})
也解析為#{{:a 3, :c 5, :b 1} {:c "2", :a 1, :b nil}}
。
我所期望的(至少從第一句話開始)是#{{:a 3, :c 55, :b 11} {:c "2", :a 1, :b 44}}
。
第一個問題:為什么我沒有得到我所期望的?
第二個問題:為什么無論參數順序如何都得到相同的結果?
萬一有人想讓我解決我開頭提到的問題
(
(fn [default, data, key]
(->> default
(map (fn [defaultEntry]
(merge
defaultEntry
(->> data (filter (fn [dataEntry] (= (key defaultEntry) (key dataEntry)))) first)
)
))
)
)
#{
{:a 1 :b nil :c "2"}
{:a 2 :b "2" :c nil}
{:a 3 :b 1 :c 5}
}
#{
{:a 1 :b 44}
{:a 3 :b 11 :c 55}
}
:a
)
(警告:假定key
是唯一的!)
從clojure.set / join代碼中,我們可以看到具有較少元素的集合用作索引,而通過查找索引中的每個元素並為每個找到的項保留合並版本,可以減少具有更多元素的集合。
(defn join
"When passed 2 rels, returns the rel corresponding to the natural
join. When passed an additional keymap, joins on the corresponding
keys."
; 2-arity version removed for brevity
([xrel yrel km] ;arbitrary key mapping
(let [[r s k] (if (<= (count xrel) (count yrel))
[xrel yrel (map-invert km)]
[yrel xrel km])
idx (index r (vals k))]
(reduce (fn [ret x]
(let [found (idx (rename-keys (select-keys x (keys k)) k))]
(if found
(reduce #(conj %1 (merge %2 x)) ret found)
ret)))
#{} s))))
這就是為什么使用(set/join ab)
或(set/join ba)
會得到相同結果的原因,除非兩組的長度相同(這不是您的情況)。
它還說明了為什么獲得#{{:a 3, :c 5, :b 1} {:c "2", :a 1, :b nil}}
而不是#{{:a 3, :c 55, :b 11} {:c "2", :a 1, :b 44}}
:存在匹配時,較長集合中的映射值優先於較短集合中的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.