【问题标题】:Custom equality in Clojure distinctClojure 中的自定义相等区别
【发布时间】:2015-10-07 17:35:47
【问题描述】:

在 Clojure 程序中,我有一个由包含人们姓名和电子邮件的地图组成的数组。

例如

[
    { :name "John" :email "john@gmail.com" }  
    { :name "Batman" :email "batman@gmail.com" }  
    { :name "John Doe" :email "john@gmail.com" }  
 ] 

我想删除重复的条目,出于比较目的,考虑到具有相同电子邮件的对是相等的。在上面的示例中,输出将是:

[
    { :name "John" :email "john@gmail.com" }  
    { :name "Batman" :email "batman@gmail.com" }  
 ] 

在 Clojure 中实现这一目标的最佳方法是什么?有没有办法让 distinct 知道使用什么 equals 函数?

谢谢。

【问题讨论】:

    标签: clojure


    【解决方案1】:

    我猜还有另一种方法,有点惯用:

    (let [items [{ :name "John" :email "john@gmail.com" }  
                 { :name "Batman" :email "batman@gmail.com" }  
                 { :name "John Doe" :email "john@gmail.com" }]]
      (map first (vals (group-by :email items))))
    

    输出:

    ({:name "John", :email "john@gmail.com"} 
     {:name "Batman", :email "batman@gmail.com"})
    

    这就是它的工作原理:

    (group-by :email items) 制作地图,其键是电子邮件,值是该电子邮件的记录组

    {"john@gmail.com" [{:name "John", :email "john@gmail.com"} 
                       {:name "John Doe", :email "john@gmail.com"}], 
     "batman@gmail.com" [{:name "Batman", :email "batman@gmail.com"}]}
    

    那么您只需要获取它的 val(记录组)并从中选择第一个。

    另一种方式是通过电子邮件创建一个排序集,因此它将所有具有相同电子邮件的记录视为相同的记录:

    (let [items [{ :name "John" :email "john@gmail.com" }  
                 { :name "Batman" :email "batman@gmail.com" }  
                 { :name "John Doe" :email "john@gmail.com" }]]
      (into (sorted-set-by #(compare (:email %1) (:email %2))) items))
    

    输出:

    #{{:name "Batman", :email "batman@gmail.com"} 
      {:name "John", :email "john@gmail.com"}}
    

    真的不知道其中哪个更惯用并且具有更好的性能。但我赌第一个。

    【讨论】:

      【解决方案2】:

      这样就可以了:https://crossclj.info/fun/medley.core/distinct-by.html

      链接中的函数懒惰地遍历每个值并存储它看到的所有内容。如果coll 中的值已经看到,则不添加。

      然后您可以将其称为:(distinct-by #(% :email) maps),其中maps 是您的人员地图向量。

      【讨论】:

      • 因为关键字是函数,所以更惯用的调用是(distinct-by :email maps)
      【解决方案3】:

      distinct-by 可以很容易地实现为

      (defn distinct-by [f coll]
        (let [groups (group-by f coll)]
          (map #(first (groups %)) (distinct (map f coll)))))
      

      对于示例情况,这可以像这样使用

      (distinct-by :email
                   [{:name "John" :email "john@gmail.com"}  
                    {:name "Batman" :email "batman@gmail.com"}  
                    {:name "John Doe" :email "john@gmail.com"}])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-13
        • 2011-04-19
        • 1970-01-01
        • 2020-07-12
        • 2018-07-05
        • 1970-01-01
        • 2015-10-18
        相关资源
        最近更新 更多