Cocktails and choreography: Array combinations and permutations in Ruby

How Ruby can help you mix the drinks and bust some moves at the charity ball

24 February 2020

24 February 2020 By Tim Ash

By Tim Ash Development

Photo: Ahmad Syahrir

As we saw in my previous post, in Ruby, Arrays are ordered lists of objects. For example:

array_of_integers = [1, 2, 3] array_of_strings = ["This", "That", "The Other"]

There are a couple of slightly obscure Array methods, combination() , and permutation() , which provide some useful functionality. combination() returns an Enumerator with all the combinations of the specified length. Perhaps an example would make that clearer (I’m using .to_a to convert the Enumerator into an Array):

$ [1, 2, 3].combination(2).to_a [[1, 2], [1, 3], [2, 3] ]

Notice that as far as combination() is concerned, [1,2] is the same as [2,1] , so only one of these is listed.

On the other hand permutation() behaves differently: it returns an Enumerator containing all the permutations of the specified length.

$ [1, 2, 3].permutation(2).to_a [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]

The crucial difference is that permutation() treats [1,2] and [2,1] as distinct.

So what use can we put this to? Let’s imagine you’ve been put in charge of organising a charity ball - your first job is to put together a list of cocktails to serve to the guests. Rather than consult a cocktail recipe book, you’ve decided to make a list of the possible cocktails you can make from the ingredients available. To save the bar staff time, each cocktail will only have two ingredients. Let’s say your list of ingredients looks like:

ingredients = ["gin", "vodka", "absinthe", "Coke", "lemonade", "milk"]

You can use combination() to produce a list of the possible cocktails:

$ ingredients.combination(2).to_a [["gin", "vodka"], ["gin", "absinthe"], ["gin", "Coke"], ["gin", "lemonade"], ["gin", "milk"], ["vodka", "absinthe"], ["vodka", "Coke"], ["vodka", "lemonade"], ["vodka", "milk"], ["absinthe", "Coke"], ["absinthe", "lemonade"], ["absinthe", "milk"], ["Coke", "lemonade"], ["Coke", "milk"], ["lemonade", "milk"]]

Well, there’s something for all tastes there, and note that, since we used combination , we haven’t ended up with separate entries for “vodka and Coke”, and “Coke and vodka”. Make mine an absinthe and milk, and we’ll move on.

The next item on your to-do list is to come up with some suggestions for some cheesy moves for the cocktail-fuelled guests as they hit the dance floor. Our list of possible dance moves looks like:

dance_moves = ["step right", "step left", "jump right", "jump left", "turn around", "clap hands", "hands on hips", "knees in tight"]

I have learned from bitter experience that the order of dance moves matter, for example a jump to the left, and then a step to the right is different to a step to the right followed by a jump to the left. For this reason, we’re going to use permutation() , rather than combination() . Assuming that four dance moves is all we can expect our guests to remember, let’s see what cheesy dances we can generate:

dance_moves.permutation(4).to_a [["jump left", "step right", "hands on hips", "knees in tight"]....

There are 1680 different ways of combining any four of these eight possible dances moves. Note that each dance move is only used once, and that the same four moves in a different order count as a different cheesy dance, in contrast to our cocktails.

I’d love to hear your thoughts on Ruby combinations, permutations, the uses you’ve found for them, and indeed, cocktails and cheesy dance moves. Why not leave a comment below?