2015-10-07 12 views
7

W programie Clojure mam tablicę złożoną z map zawierających imiona ludzi i wiadomości e-mail.Niestandardowa równość w Clojure odrębna

np.

[ 
    { :name "John" :email "[email protected]" } 
    { :name "Batman" :email "[email protected]" } 
    { :name "John Doe" :email "[email protected]" } 
] 

Chciałbym usunąć zduplikowane wpisy uwzględnianie do celów porównawczych, pary mają ten sam adres e-mail, aby być równi. W powyższym przykładzie wyjście będzie następujące:

[ 
    { :name "John" :email "[email protected]" } 
    { :name "Batman" :email "[email protected]" } 
] 

Jaki jest najlepszy sposób osiągnięcia tego w Clojure? Czy istnieje sposób, aby wyraźnie wiedzieć, co równa się funkcja używać?

Dzięki.

Odpowiedz

6

To mogłoby zrobić: https://crossclj.info/fun/medley.core/distinct-by.html.

Funkcja w łączu przechwytuje każdą wartość leniwie i przechowuje wszystko, co widzi. Jeśli wartość w coll jest już widoczna, nie dodaje jej.

Można wtedy nazwać to: (distinct-by #(% :email) maps), gdzie maps jest twoim wektorem map ludzi.

+6

Ponieważ słowa kluczowe są funkcje, bardziej idiomatycznych inwokacja byłoby '(wyraźny po: mapy e-mailowe) ' – Alex

9

Jeszcze innym sposobem, aby to zrobić, trochę bardziej idiomatyczne, myślę:

(let [items [{ :name "John" :email "[email protected]" } 
      { :name "Batman" :email "[email protected]" } 
      { :name "John Doe" :email "[email protected]" }]] 
    (map first (vals (group-by :email items)))) 

wyjściowa:

({:name "John", :email "[email protected]"} 
{:name "Batman", :email "[email protected]"}) 

, który jest, jak to działa:

(group-by :email items) sprawia mapę, której Klucze są wiadomościami e-mail, a wartości są grupami rekordów za pomocą tego adresu e-mail

{"[email protected]" [{:name "John", :email "[email protected]"} 
        {:name "John Doe", :email "[email protected]"}], 
"[email protected]" [{:name "Batman", :email "[email protected]"}]} 

następnie wystarczy wziąć jego vals (grupy rekordów) i wybrać pierwsze z nich.

A inny sposób jest stworzenie posortowanej ustawiony przez e-mail, więc będzie traktować wszystkie rekordy z równych maili jako równych zapisów:

(let [items [{ :name "John" :email "[email protected]" } 
      { :name "Batman" :email "[email protected]" } 
      { :name "John Doe" :email "[email protected]" }]] 
    (into (sorted-set-by #(compare (:email %1) (:email %2))) items)) 

wyjściowa:

#{{:name "Batman", :email "[email protected]"} 
    {:name "John", :email "[email protected]"}} 

don” t naprawdę wie, który z nich jest bardziej idiomatyczny i ma lepszą wydajność. Ale założę się na pierwszą.

0

distinct-by można łatwo wdrożyć jako

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

Dla przykładu przypadku może być używany jak

(distinct-by :email 
      [{:name "John" :email "[email protected]"} 
       {:name "Batman" :email "[email protected]"} 
       {:name "John Doe" :email "[email protected]"}])