5

I like this 6 line solution a lot and am trying to replicate it in C#. Basically, it permutes the elements of an array:

def permute(xs, pre=[]):
  if len(xs) == 0:
     yield pre
  for i, x in enumerate(xs):
     for y in permute(xs[:i] + xs[i+1:], pre + [x]):
        yield y
Chris S
  • 64,770
  • 52
  • 221
  • 239
  • Lack of tuples and rather bulky list comprehensions (i.e. LINQ) will almost certainly make the C# code clumsier, but its definitely possible to translate the code above line for line into C#. – Juliet Apr 16 '09 at 14:38
  • This is actually hard to read .. – hasen Apr 16 '09 at 17:44

4 Answers4

12

Well, it probably isn't how I'd write it, but:

static IEnumerable<T[]> Permute<T>(this T[] xs, params T[] pre) {
    if (xs.Length == 0) yield return pre;
    for (int i = 0; i < xs.Length; i++) {
        foreach (T[] y in Permute(xs.Take(i).Union(xs.Skip(i+1)).ToArray(), pre.Union(new[] { xs[i] }).ToArray())) {
            yield return y;
        }
    }
}

Re your comment; I'm not entirely clear on the question; if you mean "why is this useful?" - among other things, there are a range of brute-force scenarios where you would want to try different permutations - for example, for small ordering problems like travelling sales person (that aren't big enough to warrant a more sophisticated solution), you might want to check whether it is best to go {base,A,B,C,base}, {base,A,C,B,base},{base,B,A,C,base}, etc.

If you mean "how would I use this method?" - untested, but something like:

int[] values = {1,2,3};
foreach(int[] perm in values.Permute()) {
   WriteArray(perm);
}

void WriteArray<T>(T[] values) {
    StringBuilder sb = new StringBuilder();
    foreach(T value in values) {
        sb.Append(value).Append(", ");
    }
    Console.WriteLine(sb);
}

If you mean "how does it work?" - iterator blocks (yield return) are a complex subject in themselves - Jon has a free chapter (6) in his book, though. The rest of the code is very much like your original question - just using LINQ to provide the moral equivalent of + (for arrays).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Well done! However, you're short of one line :) How would you write it? just curious, as I prefer readability over brevity too :))) –  Apr 16 '09 at 14:21
  • Well, it would involve less LINQ, and probably two methods (one for the public caller, one separate for recursion), and a re-used buffer. Or I'd look at the links in the other post ;-p – Marc Gravell Apr 16 '09 at 14:25
  • Marc, I like your solution "a lot", However, I don't understand what it is doing... would you, or someone else, explain how to permutes over arrays and how it can be used? thanks so much –  Apr 16 '09 at 17:59
1

C# has a yield keyword that I imagine works pretty much the same as what your python code is doing, so it shouldn't be too hard to get a mostly direct translation.

However this is a recursive solution, so for all it's brevity it's sub-optimal. I don't personally understand all the math involved, but for good efficient mathematical permutations you want to use factoradics. This article should help:
http://msdn.microsoft.com/en-us/library/aa302371.aspx

[Update]: The other answer brings up a good point: if you're just using permutations to do a shuffle there are still better options available. Specifically, the Knuth/Fisher-Yates shuffle.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
0

While you cannot port it while maintaining the brevity, you can get pretty close.

public static class IEnumerableExtensions
{
  public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> source)
  {
    if (source == null)
      throw new ArgumentNullException("source");

    return PermutationsImpl(source, new T[0]);
  }

  private static IEnumerable<IEnumerable<T>> PermutationsImpl<T>(IEnumerable<T> source, IEnumerable<T> prefix)
  {
    if (source.Count() == 0)
      yield return prefix;

    foreach (var x in source)
      foreach (var permutation in PermutationsImpl(source.Except(new T[] { x }),
                                                   prefix.Union(new T[] { x }))))
        yield return permutation;
  }
}
Samuel
  • 37,778
  • 11
  • 85
  • 87
-6

Not entirely to the point I must admit after some comments, but the code below can be used to generate a random permutation of a finite sequence. It's a variation of the Fisher-Yates shuffle algorithm. The example uses a sequence of int's but you can use any Enumerable<T> of course.

var ints = Enumerable.Range(0, 51);
var shuffledInts = ints.OrderBy(a => Guid.NewGuid());

You order by a random value (in this case a Guid) which essentially permutates your list. Whether NewGuid is a good source of randomness is debatable, but it's an elegant and compact solution (albeit for another problem then the question was actually about).

Taken from Jeff Atwood (Coding Horror).

Ronald Wildenberg
  • 31,634
  • 14
  • 90
  • 133
  • 1
    How does this perform any permutations...? – Adam Robinson Apr 16 '09 at 14:07
  • +1 for a try... rwwilden would you do it with output as well? –  Apr 16 '09 at 14:10
  • If you order by a random value (a Guid in this case), you essentially permutate your list. – Ronald Wildenberg Apr 16 '09 at 14:22
  • @rwwilden: permute != shuffle – Lucas Apr 16 '09 at 14:40
  • shuffles are like a special case of a permutation, in that you can use permutations to shuffle accurately (if more slowly than with a specialized algorithm). Even the wikipedia article above mentions Fisher-Yates as "based on the same principle". – Joel Coehoorn Apr 16 '09 at 14:50
  • Even so, ordering by a new guid is not the best idea, and while all shuffles are permutations, not all permutations are good shuffles. – Joel Coehoorn Apr 16 '09 at 14:52
  • After reading up on permutations I see that I have answered this one incorrect, sorry for that. However, the method described is a good way for generating random permutations of a finite set, although not as fast as possible (and the source of randomness is debatable). Updated my answer. – Ronald Wildenberg Apr 16 '09 at 17:33