Pairwise iterator

Imagine you have a vector [1,2,3,4] and would like to have easily access adjacent elements:

(1,2)
(2,3)
(3,4)

I used to do it with a for loop and then just access the i-th and i+1-th element while looping over 1 to length()-1. This seems rather ugly so I made a pairwise iterator

pairwise(x) = zip(x, last(Iterators.peel(x)))

then with

for (x,y) in pairwise("abcd")
    @show x*y
end

you get

x * y = "ab"
x * y = "bc"
x * y = "cd"

Am I reinventing the wheel? Is there anything better?

1 Like

Would this work?

pair2(x,i) = (x[i], x[i+1])

Use broadcasting to spit out the complete set:

pair2.(Ref(x),1:length(x)-1)

That would not work with e.g. OffsetArrays.jl. It will also not work with stuff like dictionaries that are not indexable. That is why I said I don’t like the i-th element solutions.

1 Like

From Introduction · IterTools

using IterTools

for i in partition(1:9, 2, 1)
    @show i
end

# i = (1, 2)
# i = (2, 3)
# i = (3, 4)
# i = (4, 5)
# i = (5, 6)
# i = (6, 7)
# i = (7, 8)
# i = (8, 9)

d = Dict(:a => 1, :b => 2, :c => 3)

for i in partition(d, 2, 1)
    @show i
end

# i = (:a => 1, :b => 2)
# i = (:b => 2, :c => 3)

4 Likes

@owiecc, sorry for not having read you well.

I discovered today that

pairwise(xs) = IterTools.partition(xs, 2, 1)

works correctly on iterators that can only be consumed once – such as eachline(“somefile”) – while the above solution

pairwise(xs) = zip(xs, last(Iterators.peel(xs)))

and the solution I had in my own code

pairwise(xs) = zip(xs, Iterators.drop(xs, 1))

both produce the wrong result. Thanks for pointing it out!

1 Like