User Equality in Clojure

In the Clojure program, I have an array consisting of maps containing the names of people and emails.

eg.

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

I would like to remove duplicate entries, considering for comparison purposes the pairs having the same email are equal. In the above example, the output will look like this:

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

What is the best way to achieve this in Clojure? Is there a way to let individual professionals know what to use equal functions?

Thanks.

+7
clojure
source share
3 answers

That would do it: https://crossclj.info/fun/medley.core/distinct-by.html .

The function in the link goes through each value lazily and saves everything that it sees. If the value in coll already visible, it does not add it.

Then you could call it this: (distinct-by #(% :email) maps) , where maps is your people map vector.

+6
source share

another way to do this, more curious, I think:

 (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)))) 

exit:

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

this is how it works:

(group-by :email items) makes a card whose keys are emails, and the values ​​are groups of records with this email address

 {" 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 "}]} 

then you just need to take your shafts (groups of records) and choose the first from them.

And another way is to create a sorted email set so that it treats all records with the same email addresses as equal records:

 (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)) 

exit:

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

they really don’t know which one is more idiomatic and has better performance. But I bet on the first.

+9
source share

A distinct-by can be easily implemented as

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

In the sample example, this can be used as

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

All Articles