Some time ago Bozhidar Batsov wrote such tweet:
I wonder why `max-key` and `min-key` in Clojure are not named `max-by` and `min-by`. Pretty sure few people are aware what they actually do.
— Bozhidar Batsov (@bbatsov) December 19, 2015
I agree with him. Those two functions are quite useful, but their names are really misleading. Let’s look at theme to understand what they do.
max-key
As usual let’s start with function signature and its description:
(max-key k x)
(max-key k x y)
(max-key k x y & more)
Returns the x for which (k x), a number, is greatest.
At first I had a problem with understanding this doc string, so let’s paraphrase it. max-key
selects an item, from the given items, for which function k
returns biggest number. Please notice that k
must return a number, otherwise you get an exception.
Let’s look at few examples:
- Let’s find a tuple with the biggest number at the second position
(max-key second ["Jon" 1] ["Rich" 6] ["Nancy" 3])
=> ["Rich" 6]
- Let’s find a man with the biggest salary
(max-key :salary
{:name "John" :salary 200}
{:name "Andy" :salary 150}
{:name "George" :salary 205})
=> {:name "George", :salary 205}
(max-key #(get-in % [:job :salary])
{:name "John" :job {:salary 200}}
{:name "Andy" :job {:salary 150}}
{:name "George" :job {:salary 205}})
=> {:name "George", :job {:salary 205}}
max-key
function can be used to find the biggest number when we useidentity
function as a selector (of course the more idiomatic way is to usemax
function)
(max-key identity 5 3 15 8 4)
=> 15
(max 5 3 15 8 4)
=> 15
- We can use
max-key
function to find a item in a sequence (list, vector) if we useapply
function.
(apply max-key second [["Jon" 1] ["Rich" 6] ["Nancy" 3]])
=> ["Rich" 6]
min-key
As you can guess max-key
function has its opposite function called min-key
. It works in the same way, but of course, finds an item for which function k
returns the smallest number. For form’s sake let’s write its signature:
(min-key k x)
(min-key k x y)
(min-key k x y & more)
Returns the x for which (k x), a number, is least.
Below two examples:
- Let’s find a vector with smallest number of items in it.
(min-key count [1 2 3] [:a :b :c :d] [4 100] [1 2 3])
=> [4 100]
If there is more then one matching item then the last one will be returned:
(min-key count [1 2 3] [:a :b :c :d] [4 100 700] [8 1 3])
=> [8 1 3]
- Let’s find the least used character in this phrase: “lorem ipsum dolor sit amet, consectetur adipiscing elit”
(apply min-key val
(freqencies "lorem ipsum dolor sit amet, consectetur adipiscing elit"))
=> [\, 1]
Here we use frequencies
function to create a map with letters and the number of times
they appear
(frequencies "lorem ipsum dolor sit amet, consectetur adipiscing elit")
=> {\space 7,
\a 2,
\c 3,
\d 2,
\e 5,
\g 1,
\i 6,
\, 1,
\l 3,
\m 3,
\n 2,
\o 4,
\p 2,
\r 3,
\s 4,
\t 5,
\u 2}
and then we apply min-key
function to this map - the val
function is used as a function to select number from an item. In this sentence there are two characters (, and g) that appear only once. The comma
is returned as a result because it is last matching item in the collection.
I hope that my description and examples convince you that you should use and remember about max-key
and min-key
functions.