2

I have a function that is returning the following array map:

{{498 3} {-498 3}, {99 2} {-99 2}, {499 2} {-499 2}, {100 1} {-100 1}}

And I'd like to return 2, because it has the highest key, 499. Whats the best way to do this?

user3245240
  • 265
  • 4
  • 10
  • 1
    possible duplicate of [Return value of highest key in Clojure](http://stackoverflow.com/questions/26146366/return-value-of-highest-key-in-clojure) – RedDeckWins Oct 03 '14 at 23:08

5 Answers5

2

Not the most efficient way if your map is large, but it works:

(def am {{498 3} {-498 3}, {99 2} {-99 2}, {499 2} {-499 2}, {100 1} {-100 1}})

(->> am (map key) (sort-by first) last vals first) 

=> 2
Diego Basch
  • 12,764
  • 2
  • 29
  • 24
  • But why sort the whole list when just one pass through will suffice? – Mark Karpov Oct 05 '14 at 03:28
  • No reason, it was just my first thought. Perhaps it's slightly more readable than the max-key solution though. If the map is short, sorting gets lost in the noise. If it's large, then of course it's best to do one pass. – Diego Basch Oct 05 '14 at 04:23
  • Well, I still think that OP has chosen wrong data structure anyway, the solution when input is just a map is absolutely clear and readable. I cannot understand why one would use such map of maps (or array of maps) where every map is just a pair of values. – Mark Karpov Oct 05 '14 at 04:28
1
((comp val first key)
 (apply max-key
        (comp key first key)
        {{498 3} {-498 3}, {99 2} {-99 2}, {499 2} {-499 2}, {100 1} {-100 1}}))

This finds the value of the first (by spec the only?) entry in the map with the highest first key.

noisesmith
  • 20,076
  • 2
  • 41
  • 49
1

If you want to represent relations between numbers you don't need map of maps. You probably need one map like this:

user> (def foo {498 3, -498 3, 99 2, -99 2, 499 2, -499 2, 100 1, -100 1})
;; => #'user/foo

It is way more idiomatic, believe me, so may be you should consider rewriting function that returns map of maps (or vector of maps).

To solve your actual problem, try using max-key, for it is efficient function created specially for such cases. Here is how you can use it with a map:

user> (second (apply max-key first foo))
;; => 2
Mark Karpov
  • 7,499
  • 2
  • 27
  • 62
  • I am given a map of maps, not the single map you changed it to. So this answer does not work. – user3245240 Oct 06 '14 at 19:31
  • This answer is based of recommendation. What does it mean "I am given a map of maps"? Do you mean you get a map of maps from some function that you cannot change? I doubt it, because there is no need for such data structure. Map can contain many pairs 'key -> value', so you can get value 3 with key 498 and value 2 with key 99 or -99 using one single map. Unless you absolutely must use key `{498 3}` to get value `{-498 3}` there is absolutely no point in such organisation of the data. It is not idiomatic. Even if you want to able to get `{-498 3}` by key `{498 3}`, you can write a function that – Mark Karpov Oct 07 '14 at 04:20
  • ...just negates first element of the map. Please tell me why should you use a map of maps? – Mark Karpov Oct 07 '14 at 04:21
  • Because it is the return value of another function. – user3245240 Oct 07 '14 at 18:04
0

In you question you show a map with maps as keys and as values. But it seems you want to treat the keys and values like elements in a normal sequence, so I guess you actually meant the following:

[{498 3} {-498 3} {99 2} {-99 2} {499 2} {-499 2} {100 1} {-100 1}]

In that case the this function returns your wished value:

(defn val-for-highest-key
  [s]
  (->> s (map #(into [] %)) (map first) (apply max-key first) second))

test:

(def res [{498 3} {-498 3} {99 2} {-99 2} {499 2} {-499 2} {100 1} {-100 1}])
(val-for-highest-key res)

result:

=> 2
Tobias Hermann
  • 9,936
  • 6
  • 61
  • 134
  • with the input as a vector a vector, `(second (apply max-key (comp key first) res))` suffices. `flatten` is not called for here (in fact it is rarely appropriate). – noisesmith Oct 04 '14 at 03:18
  • But why sort the whole list when just one pass through will suffice? – Mark Karpov Oct 05 '14 at 03:32
  • @Mark: You are right. I corrected it. It is not beautiful, but at least now it's O(n) and no longer O(n*log(n)). ;-) Can you give me a hint on how to make the code more concise? – Tobias Hermann Oct 05 '14 at 15:36
  • @Dobi, Well noisesmith has most concise `max-key` based solution so far (mine is based on recommendation, so it is not quite correct), so take a look at [his answer](http://stackoverflow.com/a/26185794/3687048). However I found it hard to read. – Mark Karpov Oct 05 '14 at 15:40
  • Nope; I didn't "actually mean the following"; this won't work for the question that was asked. – user3245240 Oct 06 '14 at 19:31
0

Try this:

(let [fval (comp val first)
      fkey (comp key first)]
  (fval
   (reduce
    (fn [v e] (if (< (fkey v) (fkey e)) e v))
    (keys {{498 3} {-498 3}, {99 2} {-99 2}, {499 2} {-499 2}, {100 1} {-100 1}}))))
AstroCB
  • 12,337
  • 20
  • 57
  • 73
Symfrog
  • 3,398
  • 1
  • 17
  • 13