Functional Snippet #10: Permutations

In this snippet we’ll look at how to generate all permutations of the elements of an array. First we need to define the auxiliary function between. It computes all possible ways to insert an element x into an array ys. We could use a for-loop to accomplish this, but here we’ll use map, decompose and recursion instead:

func between<T>(x: T, ys: [T]) -> [[T]] {
    if let (head, tail) = ys.decompose {
        return [[x] + ys] + between(x, tail).map { [head] + $0 }
    } else {
        return [[x]]

If ys is an empty array, there’s only one way to insert x and therefore the return value is [[x]]. When ys is non-empty, we can either insert x as the very first element ([[x] + ys]) or somewhere in the tail of the array. To accomplish the latter, we make the recursive call between(x, tail) and reconstruct the original array by adding head to the front of all these possible insertions.

between(0, [1, 2, 3])

> [[0, 1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3], [1, 2, 3, 0]]

To define the permutations function we use the same pattern: decomposing the array and recursing on the tail.

func permutations<T>(xs: [T]) -> [[T]] {
    if let (head, tail) = xs.decompose {
        return permutations(tail) >>= { permTail in
            between(head, permTail)
    } else {
        return [[]]

If xs is empty, there’s only one permutation: [[]]. If xs is non-empty, we first calculate all possible permutations of the tail of xs. For each of these permutations, we calculate the different ways to insert the first element of the original array, head, into the permuted tail by calling between(head, permTail). We could use map to do so, but this would return a value of type [[[T]]] rather than [[T]]. Therefore we use the flatmap operator (>>=) on arrays defined in a previous snippet to combine the results.

permutations([1, 2, 3])

> [[1, 2, 3], [2, 1, 3], [2, 3, 1],
   [1, 3, 2], [3, 1, 2], [3, 2, 1]]

Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts