Come usare LINQ per trovare tutte le combinazioni di n elementi da un insieme di numeri?

Sto provando a scrivere un algoritmo per selezionare tutte le combinazioni di n valori da un insieme di numeri.

Ad esempio, dato il set: 1, 2, 3, 7, 8, 9

Tutte le combinazioni di 2 valori dall’insieme sono:

(1, 2), (1, 3), (1, 7), (1, 8), (1, 9), (2, 3), (2, 7), (2, 8), (2 , 9), (3, 7), (3, 8), (3, 9), (7, 8), (7, 9), (8, 9)

E 3 è:

(1, 2, 3), (1, 2, 7), (1, 2, 8), (1, 2, 9), (1, 3, 7), (1, 3, 8), (1 , 3, 9), (1, 7, 8), (1, 7, 9), (1, 8, 9), (2, 3, 7), (2, 3, 8), (2, 3 , 9), (2, 7, 8), (2, 7, 9), (2, 8, 9), (3, 7, 8), (3, 7, 9), (3, 8, 9 ), (7, 8, 9)

eccetera!

Attualmente sto usando i metodi per ottenere serie di combinazioni di ritorno di 2, 3 e 4 valori, ma mi sembra che questo potrebbe essere generalizzato in una query LINQ.

Grazie per l’aiuto!

Uso:

 var results = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.DifferentCombinations(3); 

Codice:

 public static class Ex { public static IEnumerable> DifferentCombinations(this IEnumerable elements, int k) { return k == 0 ? new[] { new T[0] } : elements.SelectMany((e, i) => elements.Skip(i + 1).DifferentCombinations(k - 1).Select(c => (new[] {e}).Concat(c))); } } 

Anche se la risposta sopra è molto accurata, ho trovato una soluzione che può essere molto più veloce a seconda delle dimensioni della collezione.

 static class Combinations { private static void InitIndexes(int[] indexes) { for (int i = 0; i < indexes.Length; i++) { indexes[i] = i; } } private static void SetIndexes(int[] indexes, int lastIndex, int count) { indexes[lastIndex]++; if (lastIndex > 0 && indexes[lastIndex] == count) { SetIndexes(indexes, lastIndex - 1, count - 1); indexes[lastIndex] = indexes[lastIndex - 1] + 1; } } private static List TakeAt(int[] indexes, IEnumerable list) { List selected = new List(); for (int i = 0; i < indexes.Length; i++) { selected.Add(list.ElementAt(indexes[i])); } return selected; } private static bool AllPlacesChecked(int[] indexes, int places) { for (int i = indexes.Length - 1; i >= 0; i--) { if (indexes[i] != places) return false; places--; } return true; } public static IEnumerable> GetDifferentCombinations(this IEnumerable collection, int count) { int[] indexes = new int[count]; int listCount = collection.Count(); if (count > listCount) throw new InvalidOperationException($"{nameof(count)} is greater than the collection elements."); InitIndexes(indexes); do { var selected = TakeAt(indexes, collection); yield return selected; SetIndexes(indexes, indexes.Length - 1, listCount); } while (!AllPlacesChecked(indexes, listCount)); } }