truffle
truffle

Reputation: 555

How do I check for duplicates within a map in clojure?

So I have a list like the following:

({:name "yellowtail", :quantity 2} {:name "tuna", :quantity 1} 
{:name "albacore", :quantity 1} {:quantity 1, :name "tuna"})

My goal is to search the list of map items and find duplicates keys, if there are duplicates then increment the quantity. So in the list I have two tuna mapped elements that show up. I want to remove one and just increment the quantity of the other. So the result should be:

({:name "yellowtail", :quantity 2} {:name "tuna", :quantity 2} 
{:name "albacore", :quantity 1} )

With :quantity of tuna incremented to 2. I have attempted to use recur to do this without success, I'm not sure if recur is a good direction to run with. Could someone point me in the right direction?

Upvotes: 6

Views: 1982

Answers (3)

Thumbnail
Thumbnail

Reputation: 13473

Why not just hold a map from name to quantity. Instead of

({:name "yellowtail", :quantity 2} {:name "tuna", :quantity 1} 
{:name "albacore", :quantity 1} {:quantity 1, :name "tuna"})

... we have

{"yellowtail" 2, "tuna" 1, "albacore" 1}

We are using the map to represent a multiset. Several clojure implementations are available, but I haven't used them.

Upvotes: 0

JustAnotherCurious
JustAnotherCurious

Reputation: 2240

You can group-by :name your elements and then map through the grouped collection summing the values.

Something like this

(->> your-list 
  (group-by :name) 
  (map (fn [[k v]] 
         {:name k :quantity (apply + (map :quantity v))})))   

P.S. I assume you need to sum quantity of elements, because it's not clear what exactly you need to increment.

Upvotes: 6

Amith George
Amith George

Reputation: 5916

This is standard use case for map and reduce.

(->> data 
     (map (juxt :name :quantity identity)) 
     (reduce (fn [m [key qty _]] 
                (update m key (fnil (partial + qty) 0))) 
             {}) 
     (map #(hash-map :name (key %1) :quantity (val %1))))

I am using identity to return the element in case you wish to use other properties in the map to determine uniqueness. If the map only contains two fields, then you could simplify it down to

(->> data 
     (mapcat #(repeat (:quantity %1) (:name %1))) 
     (frequencies) 
     (map #(hash-map :name (key %1) :quantity (val %1))))

Upvotes: 2

Related Questions