Drop iterator shape

I am looking for the recommended way to “drop” the shape property of an iterator. Eg for

itr = Iterators.product(1:5, 1:2)

I want itr_flat such that

collect(itr_flat) == vec(collect(itr))

without, of course, collecting it first.

It is relatively straightforward to implement a wrapper that does this, just curious if it is defined anywhere, or if there is a clever way to do it.

julia> itr_flat = Iterators.take(itr, length(itr))
Base.Iterators.Take{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}}(Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:5, 1:2)), 10)

julia> collect(itr_flat)
10-element Vector{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (4, 1)
 (5, 1)
 (1, 2)
 (2, 2)
 (3, 2)
 (4, 2)
 (5, 2)

works on iterators of predetermined length, but feels a bit hackish.

On the other hand, the shape matters only when collected, right? But then you might as well do reshape(x,:) on the result.

1 Like

What about this:

itr_flat = Iterators.flatten((Iterators.product(1:5, 1:2),))
collect(itr_flat)

10-element Vector{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (4, 1)
 (5, 1)
 (1, 2)
 (2, 2)
 (3, 2)
 (4, 2)
 (5, 2)
3 Likes

Thanks for both answers. They are nice workarounds, but I think that something like an Iterators.vec would convey semantics better. I will make a PR.

EDIT Silly me, there is IterTools.ivec.

2 Likes

IterTools… Of course :man_facepalming: Good to know!

Another hack is to use comprehension with if true clause

itr = Iterators.product(1:5, 1:2)
itr_flat = (x for x in itr if true)
collect(itr_flat) == vec(collect(itr))