代码之家  ›  专栏  ›  技术社区  ›  sakh1979

Clojure:如何使用与集合/联合比较[重复]

  •  1
  • sakh1979  · 技术社区  · 7 年前

    为了举例,我们假设有两个集合:

    (def set-a #{{:id 1 :name "ABC" :zip 78759} {:id 2 :name "DEF" :zip 78759}})
    
    (def set-b #{{:id 1 :name "ABC" :zip 78753} {:id 3 :name "XYZ" :zip 78704}})
    

    我想在集合之间找到一个并集,只使用:id和:name字段。然而,如果不使用自定义比较器,我会得到集中的四个元素,因为:zip字段是不同的。

    (clojure.set/union set-a set-b)
    
    #{{:id 3, :name "XYZ", :zip 78704} {:id 1, :name "ABC", :zip 78753}
      {:id 1, :name "ABC", :zip 78759} {:id 2, :name "DEF", :zip 78759}}
    

    使用自定义比较器或比较查找两个集合之间的并集的idomatic方法是什么?

    2 回复  |  直到 6 年前
        1
  •  3
  •   Taylor Wood    7 年前

    你可以使用 group-by 为此,请执行以下操作:

    (map first (vals (group-by (juxt :id :name) (concat set-a set-b))))
    

    或螺纹:

    (->> (concat set-a set-b)
         (group-by (juxt :id :name))
         (vals)
         (map first))
    

    这是根据元素的键/值组合对元素进行分组,即。 (juxt :id :name) . 然后它抓住了 val 生成的地图的ues,然后 map s first 在此基础上获取每个分组中的第一项。

    或者使用一些专门为此构建的代码,如 distinct-by .

    注意:这些方法适用于任何集合,而不仅仅是集合。

        2
  •  1
  •   dpassen    7 年前

    如果你不介意扔掉:完全扔掉,考虑使用clojure。设置/项目。

    (clojure.set/union
     (clojure.set/project set-a [:id :name])
     (clojure.set/project set-b [:id :name]))
    
    #{{:id 3, :name "XYZ"} {:id 2, :name "DEF"} {:id 1, :name "ABC"}}