1
votes

Given the following list in Clojure:

(def pairs '[(2,1),(3,2),(2,4)])

I want to merge these based overlapping first item in the pair, and select the one with the greater second value.

ie I want them to merge into:

[(3,2),(2,4)]   

because (2,1) and (2,4) have matching first values, and (2,4) has the greater second value, so it bumps off (2,1).

My question is: How do I merge pairs based on a nested value?

This is what I attempted:

(reduce
  (fn [first-pair second-pair]
    (if (not (= (first first-pair) (first second-pair)))
      (conj first-pair second-pair)
      (if (> (second first-pair) (second second-pair))
        first-pair
        second-pair)))
  pairs
  )
2
Please add the code with what you have tried already and how it fails so we can improve on it.cfrick

2 Answers

5
votes

the simplest is to group all by first and then find max in each group:

user> (->> pairs
           (group-by first)
           vals
           (map (fn [data] (apply max-key second data))))
;;=> ((2 4) (3 2))

also you can do it in one pass, without intermediate sequences:

user> (seq (reduce (fn [acc [f s]]
                     (update acc f (fnil max Double/NEGATIVE_INFINITY) s))
                   {} pairs))
;;=> ([2 4] [3 2])
2
votes

If you don't mind the intermediate collection, you can group by first and the the max for each group. E.g.

user=> (map (partial apply max-key second) (vals (group-by first pairs)))
((2 4) (3 2))