有人可以向我解释这段代码如何生成排列吗?
我看到它正在使用递归列表构建,但我不能完全了解精确的机制。
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);
}
答案 0 :(得分:6)
首先,我要指出这依赖于Union
的排序,这是未指定的,只有在原始集合中的值是唯一的情况下才有效。将Union
更改为Concat
可以解决此问题。
我怀疑它的价格也非常昂贵。总之...
你可以通过归纳来理解它。它绝对适用于基于if
的单个元素集合。那么,让我们从那里开始。
假设我们假设它适用于这样的大小n
的集合:
{ e1, ... en }
现在让我们看看它是否适用于大小为n + 1
的集合。该调用将绕过“if”,并进入递归返回部分。所以我们离开了:
list.Select((a, i1) =>
Permute(list.Where((b, i2) => i2 != i1))
.Select(b => (new List<T> { a }).Union(b)))
.SelectMany(c => c);
SelectMany
部分只是展开了一系列收藏 - 这很简单。所以让我们关注Select
电话。它在说......
a
),我们知道它具有索引i1
...
list.Where(...)
部分)Permute
调用)...... a
,后跟“当前排列”(即new List(...).Union(b)
部分。)因此,如果我们的集合是{x,y,z},我们会得到:
{ y, z }
x
的每个集合
{ x, z }
y
的每个集合
{ x, y }
z
的每个集合
这几乎定义了“每个排列”......所以它适用于n + 1
。
鉴于基本情况和归纳步骤,它适用于任何大小或等于1的集合。