我非常喜欢这个6行解决方案,并试图在C#中复制它。基本上,它会置换数组的元素:
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
答案 0 :(得分:12)
嗯,可能不是我写的方式,但是:
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;
}
}
}
重新评论;我对这个问题并不完全清楚。如果你的意思是“为什么这有用?” - 除此之外,还有一系列蛮力场景,您可能希望尝试不同的排列 - 例如,对于小型订购问题,例如旅行销售人员(不足以保证更复杂的解决方案),您可能想检查是否最好去{base,A,B,C,base},{base,A,C,B,base},{base,B,A,C,base}等。
如果您的意思是“我将如何使用此方法?” - 未经测试,但有点像:
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);
}
如果你的意思是“它是如何运作的?” - 迭代器块(yield return
)本身就是一个复杂的主题 - 但是Jon有一个免费的章节(6)in his book。其余代码非常类似于您原来的问题 - 只使用LINQ来提供+
(对于数组)的道德等价物。
答案 1 :(得分:1)
C#有一个yield关键字,我认为它与你的python代码的工作方式非常相似,所以不应该太难以获得大多数直接翻译。
然而,这是一个递归解决方案,所以尽管它简洁,但它是次优的。我个人并不理解所涉及的所有数学,但是为了获得有效的数学排列,你想要使用factoradics。本文应该有所帮助:
http://msdn.microsoft.com/en-us/library/aa302371.aspx
[更新]:另一个答案提出了一个好点:如果你只是使用排列来进行洗牌,那么仍有更好的选择。具体来说,Knuth/Fisher-Yates shuffle。
答案 2 :(得分:0)
虽然你不能在保持简洁的同时移植它,但你可以非常接近。
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;
}
}
答案 3 :(得分:-6)
在一些评论之后我不得不承认这一点,但下面的代码可用于生成有限序列的随机排列。它是Fisher-Yates shuffle algorithm的变体。该示例使用int
的序列,但您当然可以使用任何Enumerable<T>
。
var ints = Enumerable.Range(0, 51);
var shuffledInts = ints.OrderBy(a => Guid.NewGuid());
您按照随机值(在这种情况下为Guid
)进行排序,这基本上会排列您的列表。 NewGuid是否是一个很好的随机性来源是值得商榷的,但它是一个优雅而紧凑的解决方案(虽然问题实际上是另一个问题)。