0

I have a nested Clojure map:

{
  :1 {
    :priority "Medicore"
    :somekey "SomeValue"
  },
  :2 {
    :priority "Enormous"
    :somekey "SomeValue"
  },
  :3 {
    :priority "Weeny"
    :somekey "SomeValue"
  }
}

My goal is to get the value of somekey from the map with the "highest" priority. The outer map can contain 0-n number of elements with any of the three priorities. If there are multiple entries with the highest available priority, I'm fine to take any one.

After researching some other SO questions, I thought a good way to solve this issue would be to use the sort-by function. But as my priority is not naturally sorted, I'd have to provide some custom comparator.

Is this possible? Is my approach even the right one for my goal?

1 Answer 1

1

In order to use sort-by you need to provide an ordering or your priority values. You could implement a custom comparator to compare your maps or define a keyfn for sort-by that calculate the key used for sorting. The solution with keyfn is below. Using just the keyfn return a comparable value that matches your requirements is much easier than implementing comparator. You might want to take a look at Comparators Guide.

We start defining a function to convert a string priority into its numeric representation:

(let [priorities {"Medicore" 0
                  "Enormous" 1
                  "Weeny"    2}]
  (defn priority->num [p]
    (if-let [num (priorities p)]
      num
      (throw (IllegalArgumentException. (str "Unknown priority: " p))))))

(priority->num "Enormous")
;; => 1

Now we need to calculate max priority for each map:

(defn max-priority-num [m]
  (->> m
       (vals)
       (map (comp priority->num :priority))
       (apply max)))

(max-priority-num {:1 {:priority "Medicore" :somekey "SomeValue"}
                   :2 {:priority "Enormous" :somekey "SomeValue"}
                   :3 {:priority "Weeny"    :somekey "SomeValue"}})
;; => 2

Now we can finally use sort-by:

(def m1 {:1 {:priority "Medicore" :somekey "SomeValue"}
         :2 {:priority "Medicore" :somekey "SomeValue"}
         :3 {:priority "Weeny"    :somekey "SomeValue"}})

(def m2 {:1 {:priority "Medicore" :somekey "SomeValue"}
         :2 {:priority "Enormous" :somekey "SomeValue"}
         :3 {:priority "Weeny"    :somekey "SomeValue"}})

(def m3 {:1 {:priority "Medicore" :somekey "SomeValue"}
         :2 {:priority "Medicore" :somekey "SomeValue"}
         :3 {:priority "Medicore" :somekey "SomeValue"}})

(sort-by max-priority-num [m1 m2 m3])
;; =>
({:1 {:priority "Medicore", :somekey "SomeValue"},
  :2 {:priority "Medicore", :somekey "SomeValue"},
  :3 {:priority "Medicore", :somekey "SomeValue"}}
 {:1 {:priority "Medicore", :somekey "SomeValue"},
  :2 {:priority "Medicore", :somekey "SomeValue"},
  :3 {:priority "Weeny", :somekey "SomeValue"}}
 {:1 {:priority "Medicore", :somekey "SomeValue"},
  :2 {:priority "Enormous", :somekey "SomeValue"},
  :3 {:priority "Weeny", :somekey "SomeValue"}})
Sign up to request clarification or add additional context in comments.

2 Comments

This is much easier with max-key than sort-by.
Right @amalloy, I overlooked OP wanted to get the max element, not all elements sorted! So instead of calling (sort-by max-priority-num [m1 m2 m3]), (max-key max-priority-num m1 m2 m3) or (apply max-key max-priority-num maps) would be better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.