I don’t want to collect the iterations, i would like that the iterator format the iterations as array, that is, that each element of the iterator behaves like an array, not as a tuple. This is for example what permutations in Combinatorics.jl does.
For example:
The think is, the usage of the iterator gets slower. This is true also for the solution given by @Jeff_Emanuel :
using BenchmarkTools, Transducers
n=15
y=randn(n)
P=Iterators.map(collect, Iterators.product(((1., -1.) for i=1:n)...)) # yields arrays
function foo1(P, y)
for p in P
a=p.*y
end
end
Q=Iterators.product(((1., -1.) for i=1:n)...) # yields tuples
function foo2(Q, y)
for q in Q
a=q.*y
end
end
R=Iterators.product(((1., -1.) for i=1:n)...) |> Transducers.Map(collect)
function foo3(R, y)
for r in R
a=r.*y
end
end
@btime foo1($P, $y) # 2.486 ms (65536 allocations: 11.00 MiB)
@btime foo2($Q, $y) # 1.150 ms (32768 allocations: 5.50 MiB)
@btime foo3($R, $y) # 4.689 ms (98307 allocations: 20.00 MiB)
product generates tuples. If you must convert the tuples to arrays, then you have to pay for their allocation. To avoid that conversion you need to implement your own product to generate arrays instead.
An alternative is to use the existing StaticArrays.jl package to wrap the tuples. A StaticArray is just a Tuple wrapped to behave like an array. It incurs no heap allocations in most situations.
That’s a nice trick. It seems like I get the same performance as of the original iterator.
using BenchmarkTools, Transducers, StaticArrays
n=15
y=randn(n)
P=Iterators.map(collect, Iterators.product(((1., -1.) for i=1:n)...)) # yields arrays
function foo1(P, y)
for p in P
a=p.*y
end
end
Q=Iterators.product(((1., -1.) for i=1:n)...) # yields typles
function foo2(Q, y)
for q in Q
a=q.*y
end
end
R=Iterators.product(((1., -1.) for i=1:n)...) |> Transducers.Map(collect) # yields arrays
function foo3(R, y)
for r in R
a=r.*y
end
end
S=Iterators.map(SVector, Q)
function foo4(S, y)
for s in S
a=s.*y
end
end
@btime foo1($P, $y) # 2.486 ms (65536 allocations: 11.00 MiB)
@btime foo2($Q, $y) # 1.150 ms (32768 allocations: 5.50 MiB)
@btime foo3($R, $y) # 4.689 ms (98307 allocations: 20.00 MiB)
@btime foo4($S, $y) # 1.137 ms (32768 allocations: 5.50 MiB)
@btime S=Iterators.map(SVector, Q) # 371.707 ns (2 allocations: 512 bytes)