我在clojure中有两个地图矢量
(def a [{:name "batman" :universe "DC" :email "batman@wayne.com"}
{:name "flash" :universe "DC" :email "flash@speedfreak.com"}
{:name "thor" :universe "MARVEL" :email "thor@asgard.com"}])
(def b [{:name "batman" :universe "DC" :email "batman@wayne.com"}
{:name "flash" :universe "DC" :email "flash1@speedfreak.com"}
{:name "thor" :universe "MARVEL" :email "thor@asgard.com"}
{:name "riddler" :universe "DC" :email "riddler@whoami.com"}])
两个列表中的:name
属性始终同步;即,batman
中的a
始终batman
b
。{/ p>
但是,我想要做的只是选择电子邮件不匹配的行。
(stuck-on-what-to-write-here)
=> ({:name "flash", :universe "DC", :email "flash1@speedfreak.com"})
如果我用
过滤掉行(filter #(not (contains? (set (map :email a)) (:email %))) b)
它返回2行,其中一行flash
因为它不匹配而另一行riddler
因为..好吧,它不在a中,因此不匹配!
我需要做些什么来获得闪光而不是谜语?
答案 0 :(得分:3)
(defn mismatch?
"Returns true if there is any mismatch between corresponding items."
[a b]
(= (count (clojure.set/union (set a) (set b)))
(max (count a) (count b))))
如果你想要一个特定的名字,你可以使用列表理解:
(defn get-mismatched-emails
"Returns the name of any superheroes with inconsistent contact records."
[a b]
(for [i a j b
:when (and (= (:name i) (:name j))
(not= (:email i) (:email j)))]
(:name i)))
请注意,此函数效率较低,因为它必须比较两个列表之间的每对组合。只需将数据结构更改为地图地图即可:
{"batman" {:universe "DC" :email "batman@wayne.com"}
"flash" {:universe "DC" :email "flash@speedfreak.com"}
"thor" {:universe "MARVEL" :email "thor@asgard.com"}}
您宁愿轻松地将您想要的内容扩展到更大的数据集。
(for [name (clojure.set/union (set (keys a))
(set (keys b)))
:when (detect-mismatched-data (a name) (b name))]
name)
答案 1 :(得分:2)
一种可能的方法是在电子邮件中为您的过滤器添加第二个条件。我不知道galdre's answer以上的表现!
(def a-names (set (map :name a)))
(def a-emails (set (map :email a)))
(filter #(and
(contains? a-names (:name %))
(not (contains? a-emails (:email %))))
b)
这将输出({:name "flash", :universe "DC", :email "flash1@speedfreak.com"})
也不是说我把(set (map :name a))
放在了过滤器之外,所以它不需要循环来收集b中每个项目的名称。
答案 2 :(得分:0)
尝试:
(filter #(not (contains? (set (map :email b)) (:email %))) a)
返回:
({:universe "DC", :name "flash", :email "flash@speedfreak.com"})