Iterator powers?

How to get something like (0:7)^4, but for a custom iterator, and for an arbitrary positive integer exponent? The result should be similar to Iterators.product(0:7, 0:7, 0:7, 0:7), but type stable.

julia> it = (i for i in rand(1:10, 20))
Base.Generator{Vector{Int64}, typeof(identity)}(identity, [3, 2, 8, 10, 1, 7, 4, 6, 7, 2, 4, 1, 6, 8, 9, 7, 4, 1, 10, 2])

julia> map(x -> x^5, it)
20-element Vector{Int64}:
    243
     32
  32768
 100000
      1
# ...

?

No, I want something like this, but type stable:

iter_pow(it, n) = Iterators.product([it for i in 1:n]...)
1 Like

Interesting question. I doubt this is the best answer, but:

julia> A × B = (Iterators.Flatten((a, b)) for a in A for b in B)
× (generic function with 1 method)

julia> reduce(×, 0:4 for _ in 1:3)
Base.Iterators.Flatten{Base.Generator{Base.Iterators.Flatten{Base.Generator{UnitRange{Int64}, var"#52#53"{UnitRange{Int64}}}}, var"#52#53"{UnitRange{Int64}}}}(Base.Generator{Base.Iterators.Flatten{Base.Generator{UnitRange{Int64}, var"#52#53"{UnitRange{Int64}}}}, var"#52#53"{UnitRange{Int64}}}(var"#52#53"{UnitRange{Int64}}(0:4), Base.Iterators.Flatten{Base.Generator{UnitRange{Int64}, var"#52#53"{UnitRange{Int64}}}}(Base.Generator{UnitRange{Int64}, var"#52#53"{UnitRange{Int64}}}(var"#52#53"{UnitRange{Int64}}(0:4), 0:4))))

julia> collect(collect(i) for i in ans)
125-element Vector{Vector{Int64}}:
 [0, 0, 0]
 [0, 0, 1]
 [0, 0, 2]
# ...

where the × operator defined above might be the rare legitimate use case for defining infix operators as discussed in this other thread from today: Does anybody use the syntax `a <operator> b = ...` to define new methods for operators? - #8 by dylanxyz

This could be a useful feature in Combinatorics.jl.

1 Like

Oh, how about this?

julia> Iterators.product((0:7 for _ in 1:4)...)
Base.Iterators.ProductIterator{NTuple{4, UnitRange{Int64}}}((0:7, 0:7, 0:7, 0:7))

julia> collect(ans)
8×8×8×8 Array{NTuple{4, Int64}, 4}:
[:, :, 1, 1] =
 (0, 0, 0, 0)  (0, 1, 0, 0)  (0, 2, 0, 0)  (0, 3, 0, 0)  (0, 4, 0, 0)  (0, 5, 0, 0)  (0, 6, 0, 0)  (0, 7, 0, 0)
 (1, 0, 0, 0)  (1, 1, 0, 0)  (1, 2, 0, 0)  (1, 3, 0, 0)  (1, 4, 0, 0)  (1, 5, 0, 0)  (1, 6, 0, 0)  (1, 7, 0, 0)
 (2, 0, 0, 0)  (2, 1, 0, 0)  (2, 2, 0, 0)  (2, 3, 0, 0)  (2, 4, 0, 0)  (2, 5, 0, 0)  (2, 6, 0, 0)  (2, 7, 0, 0)
 (3, 0, 0, 0)  (3, 1, 0, 0)  (3, 2, 0, 0)  (3, 3, 0, 0)  (3, 4, 0, 0)  (3, 5, 0, 0)  (3, 6, 0, 0)  (3, 7, 0, 0)
 (4, 0, 0, 0)  (4, 1, 0, 0)  (4, 2, 0, 0)  (4, 3, 0, 0)  (4, 4, 0, 0)  (4, 5, 0, 0)  (4, 6, 0, 0)  (4, 7, 0, 0)
 (5, 0, 0, 0)  (5, 1, 0, 0)  (5, 2, 0, 0)  (5, 3, 0, 0)  (5, 4, 0, 0)  (5, 5, 0, 0)  (5, 6, 0, 0)  (5, 7, 0, 0)
 (6, 0, 0, 0)  (6, 1, 0, 0)  (6, 2, 0, 0)  (6, 3, 0, 0)  (6, 4, 0, 0)  (6, 5, 0, 0)  (6, 6, 0, 0)  (6, 7, 0, 0)
 (7, 0, 0, 0)  (7, 1, 0, 0)  (7, 2, 0, 0)  (7, 3, 0, 0)  (7, 4, 0, 0)  (7, 5, 0, 0)  (7, 6, 0, 0)  (7, 7, 0, 0)
...
1 Like

I think I’ll use this in the end:

iter_pow(it::It, ::Val{n}) where {It <: Any, n} =
  Iterators.product(
    ntuple(
      let it = it
        i -> it
      end,
      Val(n))...)
2 Likes