Iterator over variable number of arguments


#1

Suppose you want to define an iterator over the vertices of the n-dimensional unit hypercube.

In two dimensions, this is:

julia> using Iterators
julia> collect(Iterators.product([-1, 1], [-1, 1]))
4-element Array{Tuple{Int64,Int64},1}:
 (-1,-1)
 (1,-1) 
 (-1,1) 
 (1,1)

and similarly for 3d:

julia> collect(Iterators.product([-1, 1], [-1, 1], [-1, 1]))
8-element Array{Tuple{Int64,Int64,Int64},1}:
 (-1,-1,-1)
 (1,-1,-1) 
 (-1,1,-1) 
 (1,1,-1)  
 (-1,-1,1) 
 (1,-1,1)  
 (-1,1,1)  
 (1,1,1)

How to do when the dimension is not known a priori?


background: in Python this is achieved with list(itertools.product([-1, 1], repeat=n)), or even using tuple unpacking into arguments list as in list(itertools.product(*([-1, 1] for i in range(n)))).


#2

I think Base.Cartesian might have an answer?

https://docs.julialang.org/en/stable/devdocs/cartesian/

All of the example show loops but you can use it to make a generator.


#3

Does this do what you want?

julia> n=3
3

julia> collect(Iterators.product([[1,-1] for i=1:n]...))
8-element Array{Tuple{Int64,Int64,Int64},1}:
 (1,1,1)   
 (-1,1,1)  
 (1,-1,1)  
 (-1,-1,1) 
 (1,1,-1)  
 (-1,1,-1) 
 (1,-1,-1) 
 (-1,-1,-1)

#4

yes ! this ... or splat operator does the job.

thanks you both.


#5

Just for the sake of mentioning it. There is a CornerIterator in ImageTransformations that is used internally for the use-case of iterating over the corners of a n-dim hyper-cube (or hyper-rectangle I guess).

julia> using ImageTransformations

julia> collect(ImageTransformations.CornerIterator(CartesianIndex(-1,-1), CartesianIndex(1,1)))
2×2 Array{CartesianIndex{2},2}:
 CartesianIndex{2}((-1,-1))  CartesianIndex{2}((-1,1))
 CartesianIndex{2}((1,-1))   CartesianIndex{2}((1,1)) 

julia> collect(ImageTransformations.CornerIterator(CartesianIndex(-1,-1,-1), CartesianIndex(1,1,1)))
2×2×2 Array{CartesianIndex{3},3}:
[:, :, 1] =
 CartesianIndex{3}((-1,-1,-1))  CartesianIndex{3}((-1,1,-1))
 CartesianIndex{3}((1,-1,-1))   CartesianIndex{3}((1,1,-1)) 

[:, :, 2] =
 CartesianIndex{3}((-1,-1,1))  CartesianIndex{3}((-1,1,1))
 CartesianIndex{3}((1,-1,1))   CartesianIndex{3}((1,1,1)) 

#6

Can it also iterate over “edges” in a hyper cube?


#7

If you are asking me if I know of a similar iterator somewhere that goes along each edge, then I am afraid I don’t.