All vectors formed by picking one element from each vector

I’d like to write a vararg function which takes N vectors, and return all possible length-N vectors by picking one element from each vector. For example

all_vectors([['a', 'b'], [1, 2, 3], ['x']])

should give the result

[['a', 1, 'x'], ['a', 2, 'x'], ['a', 3, 'x'], ['b', 1, 'x'], ['b', 2, 'x'], ['b', 3, 'x']]

Although it’s not hard to write such a function, I’m wondering what the most concise and readable solution would look like.

Check out the built-in Iterators.product function:

help?> Iterators.product

  Return an iterator over the product of several iterators. Each generated element is a tuple whose ith element comes from the ith argument iterator. The first iterator changes the fastest.


  julia> collect(Iterators.product(1:2, 3:5))
  2×3 Array{Tuple{Int64,Int64},2}:
   (1, 3)  (1, 4)  (1, 5)
   (2, 3)  (2, 4)  (2, 5)

Note that product expects each iterator to be a separate argument, so you can take the product of an array of iterators by doing product(my_vector_of_vectors...) using ... to splat the collection into multiple arguments.

Also, you may get better performance by storing a tuple of vectors instead of a vector of vectors, since your individual inner vectors have different types. That would look like:

julia> data = (['a', 'b'], [1, 2, 3], ['x'])
(['a', 'b'], [1, 2, 3], ['x'])

julia> Iterators.product(data...)

Wow, that’s a very quick solution, thanks!