使用相同字母的排列

时间:2012-03-09 13:48:11

标签: c# algorithm permutation

我目前正在开展一个项目,我需要从一组给定的字符中生成所有可能的排列。我目前正在使用此代码:

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作为输入,我需要它来生成aaaaadcc等组合。

我对LINQ没有足够的经验来理解代码停止重复字母的位置。非常感谢任何帮助。

3 个答案:

答案 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());