How to use Enumerator::Product in Ruby 3.2

Ruby 3.2 brings a convenient new addition that enables combining elements from various arrays or enumerable objects with ease. Enumerator::Product, one of the most convenient new methods, can be especially useful when working with large data sets or when generating combinations for testing purposes.

For example, let’s say you have two arrays:

1
2
pastas = ["ravioli", "linguine", "penne"]
sauces = ["marinara", "bolognese", "pesto"]

Using the product method, you can easily generate all possible combinations of pastas and sauces, like so:

1
2
3
4
pastas.to_enum.product(sauces).to_a
# => [["ravioli", "marinara"], ["ravioli", "bolognese"], ["ravioli", "pesto"],
["linguine", "marinara"], ["linguine", "bolognese"], ["linguine", "pesto"],
["penne", "marinara"], ["penne", "bolognese"], ["penne", "pesto"]]

You can also chain multiple calls to product to generate more complex combinations. For example, let’s say you also have an array of toppings:

1
toppings = ["grated cheese", "olive oil"]

You can generate all possible combinations of pastas, sauces, and toppings like this:

1
2
3
4
5
6
7
8
9
10
pastas.to_enum.product(sauces, toppings).to_a
# => [["ravioli","marinara","grated cheese"], ["ravioli","marinara","olive oil"],
["ravioli","bolognese","grated cheese"], ["ravioli","bolognese","olive oil"],
["ravioli","pesto","grated cheese"], ["ravioli","pesto","olive oil"],
["linguine","marinara","grated cheese"], ["linguine","marinara","olive oil"],
["linguine","bolognese","grated cheese"], ["linguine","bolognese","olive oil"],
["linguine","pesto","grated cheese"], ["linguine","pesto","olive oil"],
["penne","marinara","grated cheese"], ["penne","marinara","olive oil"],
["penne","bolognese","grated cheese"], ["penne","bolognese","olive oil"],
["penne","pesto","grated cheese"], ["penne","pesto","olive oil"]]

Another use case of the product method is to use it in combination with other Enumerator methods. For example, you can use Enumerator#map method to apply a transformation to each combination generated by product, like this:

1
2
pastas.to_enum.product(sauces).map { |pasta, sauce| "#{pasta} #{sauce}" }.to_a
# => ["ravioli marinara", "ravioli bolognese", "ravioli pesto", "linguine marinara", "linguine bolognese", "linguine pesto", "penne marinara", "penne bolognese", "penne pesto"]

You can also use the product method with a block, which can be useful for performing operations on each combination. For example, you can use it to generate all possible combinations of pastas and sauces, and then use a block to check if any combination matches some condition, like so:

1
2
pastas.to_enum.product(sauces).any? { |pasta, sauce| pasta == "ravioli" && sauce == "pesto" }
# => true

The new Enumerator::Product method can be an extremely useful tool when working with arrays.