Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Clojure: See Every Step of a Reduce

DZone's Guide to

Clojure: See Every Step of a Reduce

· Java Zone
Free Resource

Build vs Buy a Data Quality Solution: Which is Best for You? Gain insights on a hybrid approach. Download white paper now!

Last year I wrote about a Haskell function called scanl which returned the intermediate steps of a fold over a collection and last week I realised that I needed a similar function in Clojure to analyse a reduce I’d written.

A simple reduce which adds together the numbers 1-10 would look like this:

> (reduce + 0 (range 1 11))
55

If we want to see the intermediate values of this function called then instead of using reduce there’s a function called reductions which gives us exactly what we want:

> (reductions + 0 (range 1 11))
(0 1 3 6 10 15 21 28 36 45 55)

I found this function especially useful when analysing my implementation of the Glicko ranking algorithm to work out whether a team’s ranking was being updated correctly after a round of matches.

I initially thought the reductions function was only useful as a debugging tool and that you’d always end up changing your code back to use reduce after you’d solved the problem but I realise I was mistaken.

As part of my implementation of the Glicko algorithm I wrote a bit of code that applied a reduce across a collection of football seasons and initially just returned the final ranking of each team:

(def initial-team-rankings { "Man Utd" {:points 1200} "Man City" {:points 1300}})
 
(defn update-team-rankings [teams year]
  (reduce (fn [ts [team _]] (update-in ts [team :points] inc)) teams teams))
> (reduce update-team-rankings initial-team-rankings (range 2004 2013))
{"Man City" {:points 1309}, "Man Utd" {:points 1209}}

I realised it would actually be quite interesting to see the rankings after each season for which reductionscomes in quite handy.

For example if we want to find the rankings after 3 seasons we could write the following code:

> (nth (reductions update-team-rankings initial-team-rankings (range 2004 2013)) 3)
{"Man City" {:points 1303}, "Man Utd" {:points 1203}}

Or we could join the result back onto our collection of years and create a map so we can look up the year more easily:

(def final-rankings
  (zipmap (range 2003 2013) (reductions update-team-rankings initial-team-rankings (range 2004 2013))))
> (get final-rankings 2006)
{"Man City" {:points 1303}, "Man Utd" {:points 1203}}

Build vs Buy a Data Quality Solution: Which is Best for You? Maintaining high quality data is essential for operational efficiency, meaningful analytics and good long-term customer relationships. But, when dealing with multiple sources of data, data quality becomes complex, so you need to know when you should build a custom data quality tools effort over canned solutions. Download our whitepaper for more insights into a hybrid approach.

Topics:

Published at DZone with permission of Mark Needham, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}