Counting occurences
One asked me how to count occurrences of each value in a collection. I answered (reduce #(assoc %1 %2 (inc (%1 %2 0))) {} coll)
. Since it can take some time to get accustomed to the functional way of thought, here is how one can work such an expression out:
- How to count all occurrences of 42?
(count (filter #{42} coll))
- How to express count using
reduce
? (defn my-count [coll] (reduce (fn [n _] (inc n)) 0 coll))
- How to count all occurrences of 42 using
reduce
? (reduce (fn [n _] (inc n)) 0 (filter #{42} coll))
- Can you get rid of the
filter
? (reduce (fn [n x] (if (= 42 x) (inc n) n)) 0 coll)
- I’d like the result to be
{42 occurences-count}
. (reduce (fn [m x] (if (= 42 x) (assoc m 42 (inc (m 42))) m)) {42 0} coll)
- 42 is hardcoded in four places, it’s bad!
(reduce (fn [m x] (if (= 42 x) (assoc m x (inc (m x))) m)) {42 0} coll)
- Can’t you replace
{42 0}
with{}
? - No
(inc (m x))
would fail because(m x)
would returnnil
. - How does one provide a default value when the key is not found ?
(a-map a-key default-value)
- Can’t you replace
{42 0}
with{}
? (reduce (fn [m x] (if (= 42 x) (assoc m x (inc (m x 0))) m)) {} coll)
- I changed my mind I’d like you to count occurrences of each value.
- Easy!
(reduce (fn [m x] (assoc m x (inc (m x 0)))) {} coll)
or, terser,(reduce #(assoc %1 %2 (inc (%1 %2 0))) {} coll)
Exercise:
- What does
(merge-with + {:a 12} {:b 4} {:a 3 :b 7})
return? - Can you count occurrences of each value in a collection using
merge-with
?
I like your explanation. Couldn’t be clearer.
But it seems that clojure.core now has a (frequencies coll) function that does this.
My thought process on this would probably be something like:
What does the final result need to look like?
{:a 5, :b 1, :c 4}
Can I build that up incrementally (as opposed to multiple passes)?
Yes, given {:a 5, :b 1, :c 4} and another occurrence of :b, I can produce {:a 5, :b 2, :c 4}. Good, so no post-processing or multi-pass processing is needed.
Is there a good initial condition?
{}
etc.
Very interesting blogs – I am also reading your excellent book (when’s the next edition?)
Counting occurrences using merge-with:
(reduce #(merge-with + %1 {%2 1}) {} coll)
euibjh nefvbv jhefvbh jef jt4rjhefdc jbt bgrfebvdj ny rjhktnmyrg
hjefn bj trgfdjn tjng jnrgn