Can someone explain to me how this code works which generates permutations?
I see that it’s using recursive list building but I can’t quite get my brain around the exact mechanics.
public static IEnumerable<IEnumerable<T>> Permute<T>(this IEnumerable<T> list)
{
if (list.Count() == 1)
return new List<IEnumerable<T>> { list };
return list
.Select((a, i1) =>
Permute(list.Where((b, i2) => i2 != i1))
.Select(b => (new List<T> { a }).Union(b)))
.SelectMany(c => c);
}
Firstly, I’d point out that this relies on the ordering of
Union, which is unspecified, and only works if the values in the original collection are unique. ChangingUniontoConcatwould fix that.I suspect it’s also frighteningly expensive. Anyway…
You can understand it by induction. It definitely works for a single element collection, based on the
if. So, let’s go from there.Suppose we start with the assumption that it works for a collection of size
nlike this:Now let’s see whether it works for a collection of size
n + 1. The call will bypass the “if”, and go into the recursive return part. So we’re left with:The
SelectManypart just flattens a collection of collections – that’s straightforward. So let’s focus on theSelectcall. It’s saying…a) in the original collection, which we know has indexi1…list.Where(...)part)Permutecall)…afollowed by the “current permutation” (That’s thenew List(...).Union(b)part.)So if our collection was { x, y, z } we’d get:
{ y, z }prefixed byx{ x, z }prefixed byy{ x, y }prefixed byzThat pretty much defines “every permutation”… so it works for
n + 1.Given the base case and the induction step, it therefore works for collections of any size greater than or equal to 1.