If you're used to something like Java then multidimensional arrays are a little different in syntax in C#.
Here's a page describing how to do them in C#. Here's a snippet from said page:
// Two-dimensional array. int[,] array2D = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } }; // The same array with dimensions specified. int[,] array2Da = new int[4, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } }; // A similar array with string elements. string[,] array2Db = new string[3, 2] { { "one", "two" }, { "three", "four" }, { "five", "six" } }; // Three-dimensional array. int[, ,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10, 11, 12 } } }; // The same array with dimensions specified. int[, ,] array3Da = new int[2, 2, 3] { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10, 11, 12 } } };
If you're interested in different combinations of things with a fixed number of them, something like this should be all you need.
If you're interested in different combinations of things with a dynamic number of them, something like this should be all you need.
(Unless you're trying to optimize performance, it's better to be readable/expressive, generally speaking.)
You may need to consider whether or not order matters (un-ordered set vs. ordered list). I would assume it doesn't from your code (in which case sorting is good to eliminate "duplicates"), but I can't tell for sure.
Here's a good example that's easy to read and modify for variations and isn't so bad for small numbers:
// -1, 0, ..., 5 var choices = Enumerable.Range(-1, 6); var possibleChoices = from a in choices from b in choices from c in choices from d in choices from e in choices select (IEnumerable<int>)new [] { a, b, c, d, e }; // Remove -1's because they represent not being in the choice. possibleChoices = possibleChoices.Select(c => c.Where(d => d >= 0)); // Remove choices that have non-unique digits. possibleChoices = possibleChoices.Where(c => c.Distinct().Count() == c.Count()); // Sort the choices to indicate order doesn't matter possibleChoices = possibleChoices.Select(c => c.OrderBy(d => d)); // Remove duplicates possibleChoices = possibleChoices.Select(c => new { Key = string.Join(",", c), Choice = c }). GroupBy(c => c.Key). Select(g => g.FirstOrDefault().Choice); foreach (var choice in possibleChoices) { Console.Out.WriteLine(string.Join(", ", choice)); }
Output:
0 1 2 3 4 0, 1 0, 2 0, 3 0, 4 1, 2 1, 3 1, 4 2, 3 2, 4 3, 4 0, 1, 2 0, 1, 3 0, 1, 4 0, 2, 3 0, 2, 4 0, 3, 4 1, 2, 3 1, 2, 4 1, 3, 4 2, 3, 4 0, 1, 2, 3 0, 1, 2, 4 0, 1, 3, 4 0, 2, 3, 4 1, 2, 3, 4 0, 1, 2, 3, 4
This is probably a little more dense to understand, hard-coded to this specific variation of combination and involves recursion but is a bit more generic/isn't hard-coded to 5 (and took 0.047s on dotnetfiddle.net instead of 0.094s). It's also completely lazy/IEnumerable.
public static void Main() { var possibleChoices = Choose(5); foreach (var choice in possibleChoices) { Console.Out.WriteLine(string.Join(", ", choice)); } } public static IEnumerable<IEnumerable<int>> Choose(int max) { var remaining = Enumerable.Range(0, max); return ChooseRecursive(remaining, Enumerable.Empty<int>()); } public static IEnumerable<IEnumerable<int>> ChooseRecursive(IEnumerable<int> remaining, IEnumerable<int> chosen) { yield return chosen; foreach (var digit in remaining) { var choices = ChooseRecursive( remaining.Where(d => d > digit), chosen.Concat(new [] { digit }) ); foreach (var choice in choices) { yield return choice; } } }
Output:
0 0, 1 0, 1, 2 0, 1, 2, 3 0, 1, 2, 3, 4 0, 1, 2, 4 0, 1, 3 0, 1, 3, 4 0, 1, 4 0, 2 0, 2, 3 0, 2, 3, 4 0, 2, 4 0, 3 0, 3, 4 0, 4 1 1, 2 1, 2, 3 1, 2, 3, 4 1, 2, 4 1, 3 1, 3, 4 1, 4 2 2, 3 2, 3, 4 2, 4 3 3, 4 4