我目前正在开展一个项目,我需要从一组给定的字符中生成所有可能的排列。我目前正在使用此代码:
public static IEnumerable<string> AllPermutations(this IEnumerable<char> s)
{
return s.SelectMany(x =>
{
var index = Array.IndexOf(s.ToArray(), x);
return s.Where((y, i) => i != index).AllPermutations().Select(y => new string(new[] { x }.Concat(y).ToArray())).Union(new[] { new string(new[] { x }) });
}).Distinct();
}
来自this回答。
我遇到的问题是它不会生成多次使用同一个字母的permuations。
例如,如果我使用abcde
作为输入,我需要它来生成aaaaa
和dcc
等组合。
我对LINQ没有足够的经验来理解代码停止重复字母的位置。非常感谢任何帮助。
答案 0 :(得分:3)
这个可能有效,但我确信它可以更有效地完成(从PeskyGnat获取计数提示):
static IEnumerable<string> GetVariations(string s)
{
int[] indexes = new int[s.Length];
StringBuilder sb = new StringBuilder();
while (IncrementIndexes(indexes, s.Length))
{
sb.Clear();
for (int i = 0; i < indexes.Length; i++)
{
if (indexes[i] != 0)
{
sb.Append(s[indexes[i]-1]);
}
}
yield return sb.ToString();
}
}
static bool IncrementIndexes(int[] indexes, int limit)
{
for (int i = 0; i < indexes.Length; i++)
{
indexes[i]++;
if (indexes[i] > limit)
{
indexes[i] = 1;
}
else
{
return true;
}
}
return false;
}
编辑:根据罗林斯建议更改为使用收益率回报。如果您不需要保留所有结果,并且可以在生成结果之前开始使用结果,那么内存使用会更好。
答案 1 :(得分:3)
我很惊讶这个作品。它基本上是“从字符中创建一个字符串列表。然后从列表中取出每个字符串,再次添加每个字符,并将结果字符串添加到列表中。重复直到你得到正确的长度。”
public static IEnumerable<string> BuildStrings(this IEnumerable<char> alphabet)
{
var strings = alphabet.Select(c => c.ToString());
for (int i = 1; i < alphabet.Count(); i++)
{
strings = strings.Union(strings.SelectMany(s => alphabet.Select(c => s + c.ToString())));
}
return strings;
}
答案 2 :(得分:0)
一个有趣的人,只通过一个固定点操作符使用递归lambda(对于 SelectMany ,使用@Rawling)
// Fix point operator
public static Func<T, TResult> Fix<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> f)
{
return t => f(Fix<T, TResult>(f))(t);
}
然后
var chars = new[] {'a','b','c','d','e'}.Select(c=>c.ToString()) ;
var result = Fix<int,IEnumerable<string>>(
f =>
x =>
x == 1
? chars
: chars.Union(f(x - 1).SelectMany(s => chars.Select(c => s + c))))(chars.Count());