2015-05-06 17 views
6

Ho un set di stringhe e voglio trovare tutte le combinazioni possibili delle stringhe e aggiungerle a un elenco. Voglio finire con un elenco di una lista di ogni combinazione di stringhe, meno il set vuoto.Combinazioni C# LINQ: tutte le combinazioni di un set senza il set vuoto

Ho creato una soluzione che fa esattamente questo con un ciclo annidato. Comunque Voglio farlo in modo più elegante, preferibilmente con LINQ, e non ne sono così esperto perché sono ancora piuttosto nuovo.

La soluzione deve avere 2^n - 1 elenchi di combinazioni in cui n è la cardinalità del set originale. Ecco un esempio corretto di quello che sto cercando:

set = {a, b, c} 

completedListOfCombinations = 
{ 
    {a}, 
    {b}, 
    {a, b}, 
    {c}, 
    {a, c}, 
    {b, c}, 
    {a, b, c} 
} 

Qui è il mio lavoro, soluzione di base ma brutto che ho realizzato con l'aiuto di: https://stackoverflow.com/a/3319652/3371287

List<string> myStrings = new List<string> { "a", "b", "c" }; 

var allCombos = new List<List<string>>(); 

for (int i = 0; i < myStrings.Count; i++) 
{ 
    int subsetCount = allCombos.Count; 
    var m = new List<string>(); 
    m.Add(myStrings[i]); 
    allCombos.Add(m); 

    for (int j = 0; j < subsetCount; j++) 
    { 
     string[] subset = new string[allCombos.ElementAt(j).Count + 1]; 
     allCombos[j].CopyTo(subset, 0); 
     subset[subset.Length - 1] = myStrings[i]; 
     allCombos.Add(subset.ToList()); 
    } 

} 

Qualcuno mi può mostrare un più elegante soluzione per questo? Ho visto soluzioni LINQ simili che creano coppie e liste cartesiane con una soglia, ma non sono stato in grado di adattarle a ciò di cui ho bisogno.

+0

Questo può essere più appropriato oltre [Code Review] (http://codereview.stackexchange.com) –

+0

possibile duplicato di [Tutte le combinazioni di elementi in N array in C#] (http://stackoverflow.com/questions/13616545/all-combinations-of-items -in-n-array-in-c-sharp) – mbeckish

risposta

11

condizione che siano forniti tutti i valori nella list sono unici:

List <String> list = new List<String> { "a", "b", "c" }; 

    var result = Enumerable 
    .Range(1, (1 << list.Count) - 1) 
    .Select(index => list.Where((item, idx) => ((1 << idx) & index) != 0).ToList()); 

Per stampare:

Console.WriteLine(String 
    .Join(Environment.NewLine, result 
    .Select(line => String.Join(", ", line)))); 

Il risultato è

a 
b 
a, b 
c 
a, c 
b, c 
a, b, c 
+0

Sì, i valori nell'elenco sono sempre univoci. Molto bene! Voglio sezionare e capire questo. – user3371287

+4

Si può pensare che contenga da 1 a 2^n-1. Se si guarda l'indice in formato binario (001 -> 010 -> 011 -> 100 -> 101 -> 110 -> 111), quindi associare ogni cifra binaria a uno dei valori della lista ("a", "b", " c "), e mostra solo quelli che sono 1 (mostrerò 0 come 0 invece di non mostrarli affatto), quindi ottieni (00a, 0b0, 0ba, c00, c0a, cb0, cba) –