2013-02-18 6 views
7

Ich weiß, es gibt ein paar ähnlich formulierte Fragen zu SO über Permutation Auflistung, aber sie scheinen nicht ganz richtig zu adressieren wirklich, was ich suche. Ich weiß, dass es einen Weg gibt, dies zu tun, aber ich zeichne ein leeres Blatt. Ich habe eine flache Datei, die dieses Format ähnelt:Teilen und verbinden Sie mehrere logische "Zweige" von String-Daten

Col1|Col2|Col3|Col4|Col5|Col6 
a|b,c,d|e|f|g,h|i 
. . . 

hier Jetzt ist der Trick: Ich habe eine Liste aller möglichen Permutationen dieser Zeilen erstellt werden soll, wo eine durch Kommata getrennte Liste in der Zeile Werte annehmen kann.

a/b/e/f/g/i 
a/b/e/f/h/i 
a/c/e/f/g/i 
a/c/e/f/h/i 
a/d/e/f/g/i 
a/d/e/f/h/i 

Diese mir scheint, wie es wäre: Zum Beispiel sollte ich ein IEnumerable<string>, die die oben genannten Zeilen als solche nehmen können:

IEnumerable<string> row = new string[] { "a", "b,c,d", "e", "f", "g,h", "i" }; 
IEnumerable<string> permutations = GetPermutations(row, delimiter: "/"); 

die folgende Sammlung von String-Daten Dies sollte erzeugen elegant in eine rekursive Methode passen, aber anscheinend habe ich einen schlechten Fall der montags und ich kann mich nicht richtig damit beschäftigen, wie ich es angehen soll. Einige Hilfe würde sehr geschätzt werden. Wie sollte GetPermutations(IEnumerable<string>, string) aussehen?

+0

Ist das Hausaufgaben? –

+0

Hah nein, ich nähere mich 40, aber danke für die Nachfrage. Nein, das ist für eine Werbeanwendung. Ich versuche, eine Konfigurationsdatei für Seiten zu lesen, auf denen bestimmte Anzeigen erscheinen. –

+0

Haben Sie Code oder Pseudo-Code zur Hand? Posting, das helfen kann, die Antwort zu erhalten, die Sie erreichen möchten. Ich kann mir ein paar Wege vorstellen, wie man es mit roher Gewalt macht, aber ich konnte es (noch) nicht in eine rekursive Methode umwandeln. – Tim

Antwort

0

Ich dachte wirklich, dies eine große rekursive Funktion sein würde, aber ich am Ende nicht, dass es so zu schreiben. Letztendlich ist dies der Code, den ich erstellt habe:

public IEnumerable<string> GetPermutations(IEnumerable<string> possibleCombos, string delimiter) 
{ 
    var permutations = new Dictionary<int, List<string>>(); 
    var comboArray = possibleCombos.ToArray(); 
    var splitCharArr = new char[] { ',' }; 

    permutations[0] = new List<string>(); 

    permutations[0].AddRange(
     possibleCombos 
     .First() 
     .Split(splitCharArr) 
     .Where(x => !string.IsNullOrEmpty(x.Trim())) 
     .Select(x => x.Trim())); 

    for (int i = 1; i < comboArray.Length; i++) 
    { 
     permutations[i] = new List<string>(); 
     foreach (var permutation in permutations[i - 1]) 
     { 
      permutations[i].AddRange(
       comboArray[i].Split(splitCharArr) 
       .Where(x => !string.IsNullOrEmpty(x.Trim())) 
       .Select(x => string.Format("{0}{1}{2}", permutation, delimiter, x.Trim())) 
       ); 
     } 
    } 

    return permutations[permutations.Keys.Max()]; 
} 

...meine Testbedingungen gab mir genau den Ausgang ich erwartet hatte:

IEnumerable<string> row = new string[] { "a", "b,c,d", "e", "f", "g,h", "i" }; 
IEnumerable<string> permutations = GetPermutations(row, delimiter: "/"); 
foreach(var permutation in permutations) 
{ 
    Debug.Print(permutation); 
} 

Dies wird die folgende Ausgabe erzeugt:

a/b/e/f/g/i 
a/b/e/f/h/i 
a/c/e/f/g/i 
a/c/e/f/h/i 
a/d/e/f/g/i 
a/d/e/f/h/i 

Vielen Dank an alle Vorschläge, sie in Aussortieren wirklich hilfreich waren, was getan werden musste in mein Verstand. Ich habe alle deine Antworten aufgestockt.

1

Ich bin mir nicht sicher, ob dies der eleganteste Ansatz ist, aber es könnte Ihnen den Anfang machen.

private static IEnumerable<string> GetPermutations(IEnumerable<string> row, 
                string delimiter = "|") 
{ 
    var separator = new[] { ',' }; 
    var permutations = new List<string>(); 
    foreach (var cell in row) 
    { 
     var parts = cell.Split(separator); 
     var perms = permutations.ToArray(); 
     permutations.Clear(); 
     foreach (var part in parts) 
     { 
      if (perms.Length == 0) 
      { 
       permutations.Add(part); 
       continue; 
      } 
      foreach (var perm in perms) 
      { 
       permutations.Add(string.Concat(perm, delimiter, part)); 
      } 
     } 
    } 
    return permutations; 
} 

Natürlich, wenn die Reihenfolge der Permutationen wichtig ist, können Sie eine .OrderBy() am Ende hinzufügen.

Edit: hat eine alernative

Sie können auch eine Liste von String-Arrays aufzubauen, indem er einige Zahlen Berechnung vor die Permutationen zu bestimmen.

private static IEnumerable<string> GetPermutations(IEnumerable<string> row, 
                string delimiter = "|") 
{ 
    var permutationGroups = row.Select(o => o.Split(new[] { ',' })).ToArray(); 
    var numberOfGroups = permutationGroups.Length; 
    var numberOfPermutations = 
      permutationGroups.Aggregate(1, (current, pg) => current * pg.Length); 
    var permutations = new List<string[]>(numberOfPermutations); 

    for (var n = 0; n < numberOfPermutations; n++) 
    { 
     permutations.Add(new string[numberOfGroups]); 
    } 

    for (var position = 0; position < numberOfGroups; position++) 
    { 
     var permutationGroup = permutationGroups[position]; 
     var numberOfCharacters = permutationGroup.Length; 
     var numberOfIterations = numberOfPermutations/numberOfCharacters; 
     for (var c = 0; c < numberOfCharacters; c++) 
     { 
      var character = permutationGroup[c]; 
      for (var i = 0; i < numberOfIterations; i++) 
      { 
       var index = c + (i * numberOfCharacters); 
       permutations[index][position] = character; 
      } 
     } 
    } 

    return permutations.Select(p => string.Join(delimiter, p)); 
} 
1

Sie hatten mich bei "rekursiv". Hier ist ein weiterer Vorschlag:

private IEnumerable<string> GetPermutations(string[] row, string delimiter, 
              int colIndex = 0, string[] currentPerm = null) 
{ 
    //First-time initialization: 
    if (currentPerm == null) { currentPerm = new string[row.Length]; } 

    var values = row[colIndex].Split(','); 
    foreach (var val in values) 
    { 
     //Update the current permutation with this column's next possible value.. 
     currentPerm[colIndex] = val; 

     //..and find values for the remaining columns.. 
     if (colIndex < (row.Length - 1)) 
     { 
      foreach (var perm in GetPermutations(row, delimiter, colIndex + 1, currentPerm)) 
      { 
       yield return perm; 
      } 
     } 
     //..unless we've reached the last column, in which case we create a complete string: 
     else 
     { 
      yield return string.Join(delimiter, currentPerm); 
     } 
    } 
} 
1

Ein Algorithmus Sie verwenden können, im Grunde wie das Zählen ist:

  • Beginnen Sie mit dem 0-ten Element in jeder Liste (00000)
  • Erhöhungsschritte der letzte Wert (00001, 00002 usw. .)
  • Wenn Sie keinen Wert erhöhen können, setzen Sie ihn zurück und erhöhen Sie den nächsten (00009, 00010, 00011 usw.)
  • Wenn Sie keinen Wert erhöhen können, sind Sie fertig.

Funktion:

static IEnumerable<string> Permutations(
    string input, 
    char separator1, char separator2, 
    string delimiter) 
{ 
    var enumerators = input.Split(separator1) 
     .Select(s => s.Split(separator2).GetEnumerator()).ToArray(); 
    if (!enumerators.All(e => e.MoveNext())) yield break; 

    while (true) 
    { 
     yield return String.Join(delimiter, enumerators.Select(e => e.Current)); 
     if (enumerators.Reverse().All(e => { 
       bool finished = !e.MoveNext(); 
       if (finished) 
       { 
        e.Reset(); 
        e.MoveNext(); 
       } 
       return finished; 
      })) 
      yield break; 
    } 
} 

Verbrauch:

foreach (var perm in Permutations("a|b,c,d|e|f|g,h|i", '|', ',', "/")) 
{ 
    Console.WriteLine(perm); 
} 
Verwandte Themen