2

I have two arrays of always equal size, and I want to find all possible combination sets of these two arrays.

For example:

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

I would like the result to be returned as a List of Dictionary:

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"}},
            ...
        };

Edit: None of the values in the two arrays can repeat itself in the dictionaries, like:

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

Any tips on how to solve this?

Edit: I don't think cartesian product can be used since it will return

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" }, 
... 
}
jimmyrn
  • 41
  • 4
  • 2
    Have you attempted this? This smells of homework, no? If it is you should read the [guidelines on homework questions](http://meta.stackexchange.com/a/10812/217110), specifically *[The OP should](that's you)Make a good faith attempt to solve the problem yourself first*. You should also read the [help] – Liam Jun 08 '16 at 09:17
  • 1
    What you are looking for is the cartesian product. There are many solutions here for that. – Rob Jun 08 '16 at 09:17
  • Possible duplicate of [Efficient Cartesian Product algorithm](http://stackoverflow.com/questions/1741364/efficient-cartesian-product-algorithm) – Liam Jun 08 '16 at 09:20
  • Yes, have tried with cartesian product, but as I see it, I will not get sets of combinations back, but only one list with combinations of the two lists like: `var cartesianProduct= new []{ new []{ "John", "A" }, new []{ "Alex", "B" }, ... }` – jimmyrn Jun 08 '16 at 09:30

2 Answers2

1

As many people mentioned in the comments, you could apply Cartesian product between two lists and do this.

Logic performs Cartesian product and then gives index to each outcome, this index used to slice and form each group (Since you want each group as dictionary).

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

Output

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]
]

Check this Demo

Hari Prasad
  • 16,716
  • 4
  • 21
  • 35
1

In a Console project, make Program class static to enable extension methods. To use this in asp.net, make a method of Main and create a static helper class for other functions.

    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 you do actually need Permutations not Combinations

Mike Tsayper
  • 1,686
  • 1
  • 17
  • 25