相交覆盖相等性的地图列表列表

时间:2016-08-28 23:43:56

标签: clojure

我有一份地图清单:

(( {:id 1 :temp 1} {:id 2} ) 
 ( {:id 1 :temp 2} )
 ( {:id 1 :temp 3} {:id 2} ))

我想通过:id键获取这3组交集的ID。所以我的结果将是1

我提出了这个解决方案,但它伤害了我的眼睛:

(def coll '(( {:id 1 :temp 1} {:id 2} )
            ( {:id 1 :temp 2} )
            ( {:id 1 :temp 3} {:id 2} )))

(apply clojure.set/intersection 
       (map set (map (fn [m] 
                         (map #(select-keys % '(:id)) m)) coll)))

返回

#{{:id 1}}

这是好的,但是还有其他建议吗?

2 个答案:

答案 0 :(得分:0)

如果你可以获得#{1}(正如你最初提到的那样)而不是#{{:id 1}},那么它可以稍微改进一下:

(apply set/intersection (map (fn [c] (into #{} (map :id c))) coll))

答案 1 :(得分:0)

(require '[clojure.set :refer [intersection]])

我猜你不需要的选择键,因为你只对id感兴趣。 (map :id m)完成最内层地图的工作。通过这个你摆脱了一个功能速记。您可以在下一张地图中使用它:

(map #(map :id  %) coll)
;; ((1 2) (1) (1 2))

您介绍的第三张地图不是必需的。它可以在上面的代码中合并:

(map (comp set #(map :id  %)) coll)

或:

(map #(set (map :id %)) coll)

评估为:(#{1 2} #{1} #{1 2})

这仍然是非常嵌套的。线程宏在这里没有帮助。但是你可以使用一个名为for的非常强大的列表推导宏:

(for [row coll]
  (set (map :id row)))

这为您提供了命名列表项(行)但同时保持简洁的优势。

最后:

(apply intersection (for [row coll]
                      (set (map :id row))))
;; #{1}