eliocs
eliocs

Reputation: 18827

How to iterate over a collection and have access to previous, current and next values on each iteration?

How can I iterate the elements of a collection in Clojure so I can access the previous, current and next values in every iteration.

With the following vector:

[1 2 3 4]

I would like to have access to the following values in each iteration:

[nil 1 2]
[1 2 3]
[2 3 4]
[3 4 nil]

Upvotes: 5

Views: 1294

Answers (3)

Alex Miller
Alex Miller

Reputation: 70211

I'd recommend the partitioning technique, but another trick is to map over staggered instances of the same sequence:

(let [s [1 2 3 4]]
  (map vector (cons nil s) 
              s
              (concat (drop 1 s) [nil])))

-> ([nil 1 2] [1 2 3] [2 3 4] [3 4 nil])

Upvotes: 4

Leon Grapenthin
Leon Grapenthin

Reputation: 9266

Here is a loop/recur implementation utilizing destructoring.

(let [s [1 2 3 4]]
  (loop [[prev & [cur nxt :as more]] (cons nil s)
         result []]
    (if (seq more)
      (recur more (conj result [prev cur nxt]))
      result)))

Upvotes: 3

user2609980
user2609980

Reputation: 10484

One way to do it is by concatting nil before and after the collection and partitioning it by elements of 3 with a step size of 1.

(def c [1 2 3 4])
(def your-fn println) ;; to print some output later
(map your-fn
     (map vec (partition 3 1 (concat [nil] c [nil]))))

(You can remove the map vec part if it is also fine if the elements are a LazySeq instead of a vector.)

Which prints:

[nil 1 2]
[1 2 3]
[2 3 4]
[3 4 nil]

Upvotes: 9

Related Questions