Skip to main content

Command Palette

Search for a command to run...

Sliding Windows in Clojure

Updated
2 min read
Sliding Windows in Clojure

I was doing a little Clojure programming and my son asked me if the computer could

make it go 1 2 3, 2 3 4, 3 4 5, …

I thought, hmm, that’s a sliding window.

Here was my first thought:

(->> (range 1 4)
     (map (fn [x] [x (inc x) (inc (inc x))])))
;;=> ([1 2 3] [2 3 4] [3 4 5])

I asked if he wanted it as just one list. He asked me to show him, so I thought… I’m mapping over this and need to concatenate the lists. Wait, that’s literally mapcat:

(->> (range 1 4)
     (mapcat (fn [x] [x (inc x) (inc (inc x))])))
;;=> (1 2 3 2 3 4 3 4 5)

He said he preferred the little lists to the one big one. Good thinking.

Then I thought, can we make it shorter? I could use iterate instead of the vector literal:

(->> (range 1 4)
     (map #(take 3 (iterate inc %))))
;;=> ((1 2 3) (2 3 4) (3 4 5))

Looking at this, it’s really easy to parameterize:

(let [window-size 3
      number-of-windows 3]
  (->> (range 1 (inc number-of-windows))
       (map #(take window-size (iterate inc %)))))
;;=> ((1 2 3) (2 3 4) (3 4 5))

Then I thought, the first number in a little collection forms the basis for the next little collection. I also like this way best because it starts with a literal vector [1 2 3]:

(->> [1 2 3]
     (iterate #(map inc %))
     (take 3))
;;=> ([1 2 3] (2 3 4) (3 4 5))

It can be parameterized as well:

(let [number-of-windows 3]
  (->> [1 2 3]
       (iterate #(map inc %))
       (take number-of-windows)))
;;=> ([1 2 3] (2 3 4) (3 4 5))

After doing all that, I realize that this isn’t a sliding window at all! In a true sliding window problem, you don’t know what the elements will be. THIS is a sliding window:

(let [window-size 3
      step-size 1]
  (partition window-size step-size (range 1 (inc 5))))
;;=> ((1 2 3) (2 3 4) (3 4 5))

In any case, Clojure is awesome for this type of work.

More from this blog

B

Brett Rowberry’s Blog

34 posts

I love to write!