It’s pretty simple with Iterators.product
:
outer_product3(vs) = Base.splat(*).(Iterators.product(vs...))
Also seems to be faster for this small example:
julia> @benchmark outer_product($vs)
BenchmarkTools.Trial: 10000 samples with 6 evaluations.
Range (min … max): 5.900 μs … 910.300 μs ┊ GC (min … max): 0.00% … 98.87%
Time (median): 6.117 μs ┊ GC (median): 0.00%
Time (mean ± σ): 6.828 μs ± 21.970 μs ┊ GC (mean ± σ): 7.83% ± 2.42%
▆▇█▇▆▆▅▅▄▃▃▂▃▃▂▂▁▂▂▁▂▁ ▁ ▁▁ ▂
████████████████████████████▇█▇█▆▇▇▆▅▆▅▅▅▅▅▅▄▆▅▅▄▅▃▃▄▂▄▆▅▆▅ █
5.9 μs Histogram: log(frequency) by time 8.47 μs <
Memory estimate: 5.11 KiB, allocs estimate: 135.
julia> @benchmark outer_product2($vs)
BenchmarkTools.Trial: 10000 samples with 10 evaluations.
Range (min … max): 1.530 μs … 488.580 μs ┊ GC (min … max): 0.00% … 98.97%
Time (median): 1.610 μs ┊ GC (median): 0.00%
Time (mean ± σ): 1.756 μs ± 4.889 μs ┊ GC (mean ± σ): 2.75% ± 0.99%
▅█
▄███▆▃▃▄▅▅▃▃▂▃▄▃▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▁▂▂▁▁▁▂▂▂▁▂▂▁▂▂▂▂▂▁▂ ▃
1.53 μs Histogram: frequency by time 2.96 μs <
Memory estimate: 752 bytes, allocs estimate: 15.
julia> @benchmark outer_product3($vs)
BenchmarkTools.Trial: 10000 samples with 176 evaluations.
Range (min … max): 605.114 ns … 13.131 μs ┊ GC (min … max): 0.00% … 92.48%
Time (median): 652.841 ns ┊ GC (median): 0.00%
Time (mean ± σ): 707.149 ns ± 606.302 ns ┊ GC (mean ± σ): 4.17% ± 4.69%
█▅▃ ▇▆▅▃▂▂▂▁ ▁ ▂▂▂▁ ▁▂▁▁ ▂
█████████████████████▆▇█████▇▇▇▆▆▆▇▆▅▅▆▆▆▁▄▃▄▇█▅▅▅██▅▇▆▆▅▄▆▅▆ █
605 ns Histogram: log(frequency) by time 1.28 μs <
Memory estimate: 672 bytes, allocs estimate: 7.