clojure.set/join的意外选择和合并行为 [英] The unexpected selection and merging behavior of clojure.set/join

查看:101
本文介绍了clojure.set/join的意外选择和合并行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用某些特定值覆盖关系中的某些默认值,并偶然发现了一些我不太了解的行为.

I wanted to overwrite some default value in a relation with some specific values and stumbled upon some behavior I don't quite understand.

(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}}.

如果我翻转参数,我将得到相同的结果.

If I flip the arguments I get the same result.

(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}}.

What I expected (at least from the first statement) was #{{:a 3, :c 55, :b 11} {:c "2", :a 1, :b 44}}.

第一个问题:为什么我没有得到我所期望的?

First question: Why don't I get what I expect?

第二个问题:为什么无论参数顺序如何都得到相同的结果?

Second question: Why do I get the same result regardless of argument order?

以防万一有人要我解决开头提到的问题

Just in case someone wants my solution to my problem stated in the beginning

(
  (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是唯一的!)

(Warning: Assumes that key is unique!)

推荐答案

来自

From the clojure.set/join code we can see that the set with fewer elements is used as an index and the set with more elements is reduced by looking for each element in the index and keeping the merged version for each found item.

(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 a b)(set/join b a)会得到相同结果的原因,除非两组长度相同(不是您的情况).

That's why you'll the get same result with (set/join a b) or (set/join b a), except if both sets are of the same length, which is not your case.

这也解释了为什么得到#{{:a 3, :c 5, :b 1} {:c "2", :a 1, :b nil}}而不是#{{:a 3, :c 55, :b 11} {:c "2", :a 1, :b 44}}的原因:存在匹配项时,较长集的映射中的值优先于较短集的映射中的值.

It also explains why you get #{{:a 3, :c 5, :b 1} {:c "2", :a 1, :b nil}} instead of #{{:a 3, :c 55, :b 11} {:c "2", :a 1, :b 44}}: The values in the maps from the longer set take precedence over the values from the shorter set when there's a match.

这篇关于clojure.set/join的意外选择和合并行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆