在C#中查找两个大小相同的数组的所有组合集

时间:2016-06-08 09:14:45

标签: c# asp.net

我有两个总是大小相等的数组,我想找到这两个数组的所有可能的组合集。

例如:

var names = new [] { "John", "Alex", "Peter", "Eric" };
var letters = new [] { "A", "B", "C", "D" };

我希望将结果作为字典列表返回:

var combinationSets = new List<Dictionary<string, string>>
        {
            new Dictionary<string, string>
            { {"John", "A"},
            {"Alex", "B"},
            {"Peter", "C"},
            {"Eric", "D"}},
            new Dictionary<string, string>
            { {"John", "B"},
            {"Alex", "C"},
            {"Peter", "D"},
            {"Eric", "A"}},
            ...
        };

编辑:两个数组中的值都不能在字典中重复,例如:

new Dictionary<string, string>
                { {"John", "A"},
                {"Alex", "A"},
                {"Peter", "C"},
                {"Eric", "D"}}

有关如何解决此问题的任何提示?

编辑: 我不认为可以使用笛卡尔积,因为它会返回

var cartesianProduct= new []
{ 
new []{ "John", "A" }, 
new []{ "Alex", "B" },     
new []{ "Peter", "C" }, 
new []{ "John", "D" }, 
new []{ "John", "B" }, 
new []{ "Alex", "C" },     
new []{ "Peter", "D" }, 
new []{ "John", "A" }, 
... 
}

2 个答案:

答案 0 :(得分:1)

正如许多人在评论中提到的那样,你可以在两个列表之间应用笛卡尔积,然后执行此操作。

Logic执行笛卡尔积,然后为每个结果提供索引,该索引用于切片和形成每个组(因为您希望每个组都作为字典)。

    var names = new [] { "John", "Alex", "Peter", "Eric" };
    var letters = new [] { "A", "B", "C", "D" };


    int index =0;   
    var results = letters.SelectMany(x => names, (x, y) => new {x, y, idx = index++})
        .GroupBy(x=>x.idx/names.Length)  // Slice each group
        .Select(x=> x.ToDictionary(s=>s.y, s=> s.x))
        .ToList();

<强>输出

Dumping object(System.Collections.Generic.Dictionary`2[String,String])
[
   [John, A]
   ,
   [Alex, A]
   ,
   [Peter, A]
   ,
   [Eric, A]
]
Dumping object(System.Collections.Generic.Dictionary`2[String,String])
[
   [John, B]
   ,
   [Alex, B]
   ,
   [Peter, B]
   ,
   [Eric, B]
]
Dumping object(System.Collections.Generic.Dictionary`2[String,String])
[
   [John, C]
   ,
   [Alex, C]
   ,
   [Peter, C]
   ,
   [Eric, C]
]
Dumping object(System.Collections.Generic.Dictionary`2[String,String])
[
   [John, D]
   ,
   [Alex, D]
   ,
   [Peter, D]
   ,
   [Eric, D]
]

选中此Demo

答案 1 :(得分:1)

在Console项目中,将Program类设为static以启用扩展方法。 要在asp.net中使用它,请创建Main方法并为其他函数创建静态助手类。

    static void Main(string[] args)
    {
        var names = new[] { "John", "Alex", "Peter", "Eric" };
        var letters = new[] { "A", "B", "C", "D" };

        var combinationSets = new List<Dictionary<string, string>>();
        foreach (var seq in letters.Permutate(4))
        {
            var dic = new Dictionary<string, string>();
            var vals = seq.ToArray();
            for (int i = 0; i < 4; i++)
            {
                dic.Add(names[i], vals[i]);
            }
            combinationSets.Add(dic);
        }

        foreach (var dic in combinationSets)
        {
            foreach (var p in dic)
            {
                Console.WriteLine(p.Key + ": " + p.Value);
            }
            Console.WriteLine();
        }
        Console.ReadLine();
    }

public static IEnumerable<IEnumerable<T>> Permutate<T>(this IEnumerable<T> elements, int places, bool allowRepeats = false)
{
    foreach (var cur in elements)
    {
        if (places == 1) yield return cur.Yield();
        else
        {
            var sub = allowRepeats ? elements : elements.ExceptOne(cur);   
            foreach (var res in sub.Permutate(places - 1, allowRepeats))
            {
                yield return res.Prepend(cur);
            }
        }
    }
}

    public static IEnumerable<T> Yield<T>(this T item)
    {
        yield return item;
    }

    static IEnumerable<T> Prepend<T>(this IEnumerable<T> rest, T first)
    {
        yield return first;
        foreach (var item in rest)
            yield return item;
    }


    public static IEnumerable<T> ExceptOne<T>(this IEnumerable<T> src, T e, int n = 1)
    {
        foreach (var x in src)
            if (!x.Equals(e) || n-- == 0) yield return x;
    }

ps你确实需要排列而不是组合