重复的排列

时间:2015-10-14 20:16:16

标签: c# algorithm generics permutation repeat

如果您能找到更好的标题,请编辑。

我首先要说的是,我已经查看了有关此主题的几个q& a,主要是this onethis article,但没有找到办法:

鉴于“HALLOWEEN”这个词,我想找到所有长度的所有排列和组合。我尝试的第一件事是迭代下面的代码,给出长度1开始并继续直到达到单词的长度(9)。

public static IEnumerable<IEnumerable<T>>
        GetPermutations<T>(IEnumerable<T> list, int length)
    {
        if (length == 1) return list.Select(t => new T[] {t});

        return GetPermutations(list, length - 1)
            .SelectMany(t => list.Where(e => !t.Contains(e)),
                (t1, t2) => t1.Concat(new T[] {t2}));
    }

这给了我意想不到的结果,因为双'E'和'L'被省略,最后的设置很短。

一个更简单的例子可能是'妈妈'{M,O,M},其中最终结果将是:

  •   

    中号

  •   

    0

  •   

    MO

  •   

    OM

  •   

    MM

  •   

    妈妈

  •   

    MMO

  •   

    OMM

请注意,我希望看到两个'M'可用,但我不希望看到“MMM”。由于离开原始顺序(1,2,3),“MOM”将在结果中出现两次,并且交换位置1和3(3,2,1)将导致'M','O','M'但这个字符序列只出现一次是结果列表(可以通过字符串比较完成)

再次,使用set {1,1,2,3},我希望看到:

{1,1}

但不是{2,2}或{3,3}

4 个答案:

答案 0 :(得分:1)

这是另一个应该清晰且易于理解的解决方案:

    public static IEnumerable<string> GetPermutations(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            return new List<string>();
        }

        var length = input.Length;
        var indices = Enumerable.Range(0, length).ToList();
        var permutationsOfIndices = GetNumericalPermutations(indices, length);

        var permutationsOfInput = permutationsOfIndices.Select(x => new string(x.Select(y => input[y]).ToArray()))
                                                       .Distinct();
        return permutationsOfInput;
    }


    private static List<List<int>> GetNumericalPermutations(List<int> values, int maxLength)
    {
        if (maxLength == 1)
        {
            return values.Select(x => new List<int>{x}).ToList();
        }
        else
        {
            var permutations = GetNumericalPermutations(values, maxLength - 1);

            foreach (var index in values)
            {
                var newPermutations = permutations.Where(x => !x.Contains(index))
                                                  .Select(x => x.Concat(new List<int> { index }))
                                                  .Where(x => !permutations.Any(y => y.SequenceEqual(x)))
                                                  .Select(x => x.ToList())
                                                  .ToList();

                permutations.AddRange(newPermutations);
            }
            return permutations;
        }
    }

例如,&#34; MOM&#34;的输出是:

M
O
OM
MM
MO
MMO
OMM
MOM

答案 1 :(得分:0)

我建议查看字母位置0,1,2,3,4等的排列,将它们映射到字母,然后消除重复。

在不更改GetPermutations函数的情况下,我添加了另一个函数来获取字母位置的排列,将这些结果映射到字符串,然后消除重复项。

cordova plugin add cordova-plugin-whitelist --save

答案 2 :(得分:0)

这很好用:

Func<string, IEnumerable<string>> getAllSubsets = null;
getAllSubsets = x =>
    (x == null || !x.Any())
        ? Enumerable.Empty<string>()
        :  (x.Length > 1
            ? getAllSubsets(x.Substring(1))
                .SelectMany(y => new [] { y, x.Substring(0, 1) + y })
            : new [] { "", x.Substring(0, 1) });

所以给定getAllSubsets("ABC")我得到:

  

&#34;&#34;,&#34; A&#34;,&#34; B&#34;,&#34; AB&#34;,&#34; C&#34;,&# 34; AC&#34;,&#34; BC&#34;,&#34; ABC&#34;

而且,对于您的"MOM"示例,我得到了:

  

&#34;&#34;,&#34; M&#34;,&#34; O&#34;,&#34; MO&#34;,&#34; M&#34;,&# 34; MM&#34;,&#34; OM&#34;,&#34; MOM&#34;

如果需要,过滤掉空字符串并重复值将是微不足道的,但是当它立即严格产生所有子集时。

答案 3 :(得分:0)

我认为通常最好避免产生和消除排列。像“aaaaaaaaaaaaaaab”这样的文字可以产生大量的重复。

public static IEnumerable<IEnumerable<T>>
GetPermutationsInner<T>(IEnumerable<IGrouping<T, T>> groupedList, int length)
{
    if (length == 1) return groupedList.Select(t => new T[] { t.Key });

    return GetPermutationsInner<T>(groupedList, length - 1)
        .SelectMany(t => groupedList
                .Where(e => t.Count(w => w.Equals(e.Key)) < e.Count())
                .Select(s => s.Key),
            (t1, t2) => t1.Concat(new T[] { t2 }));
}

public static IEnumerable<IEnumerable<T>>
    GetPermutations<T>(IEnumerable<T> list)
{
    var resultList = new List<IEnumerable<T>>();
    for (int i = 1; i <= list.Count(); ++i)
    {
        resultList.AddRange(GetPermutationsInner<T>(list.GroupBy(g => g), i));
    }
    return resultList;
}