2010-12-09 12 views
1

Ich möchte eine Sammlung von Zeichenfolgen (mit C# und möglicherweise LINQ) aus einer einzigen CSV-Zeichenfolge erstellen, wobei jeder Wert ein Plus- oder Minuszeichen gefolgt von einem Zeichen ist. Zum Beispiel:Erweiterung von Platzhaltern in einer CSV-Zeichenfolge, um eine Sammlung von CSV-Zeichenfolgen zu generieren?

Die Zeichenfolge könnte auch eine Platzhalterkarte enthalten, die zwei beliebige Zeichen darstellt. eins mit einem Pluszeichen und dann eins mit einem negativen Vorzeichen. Wenn eine Zeichenfolge eine Wildcard enthält, möchte ich die Wildcard ersetzen und eine Liste mit Zeichenfolgen ohne Platzhalter erstellen. Zum Beispiel sagen, ich habe:

"+A,-A,*" 

Die Saiten, die ich wollen würde, um sein würden zu erzeugen:

+A,-A,+A,-A 
+A,-A,+B,-B 
+A,-A,+C,-C 
+A,-A,... 
+A,-A,+Z,-Z 

Und ebenfalls für mehrere Platzhalter. Die Zeichenfolge "*,*" erzeugen würde:

+A,-A,+A,-A 
+A,-A,+B,-B 
+A,-A,+C,-C 
+A,-A,... 
+A,-A,+Z,-Z 
+B,-B,+A,-A 
+B,-B,+B,-B 
+B,-B,+C,-C 
+B,-B,... 
+B,-B,+Z,-Z 
+C,-C,... 

Mein Bauch sagt mir, es muss eine einfache, elegante Lösung, aber es entzieht mir heute. Irgendwelche Ideen? Dies scheint ein perfekter Algorithmus zu sein, um LINQ zu nutzen? Danke für deine Hilfe!

Antwort

2
IEnumerable<string> Wildcard = from c in Enumerable.Range(0, 26) 
           let ch = (char)('A' + c) 
           select string.Concat('+', ch, ',', '-', ch); 

IEnumerable<string> ExpandLine(string[] xs, int i) 
{ 
    var ys = (xs[i] == "*") ? Wildcard : new[] { xs[i] }; 

    if (i == xs.Length - 1) 
     return ys; 
    else 
     return from y in ys 
       from z in ExpandLine(xs, i + 1) 
       select y + "," + z; 
} 

IEnumerable<string> ExpandLines(IEnumerable<string> xs) 
{ 
    return from x in xs 
      from y in ExpandLine(x.Split(','), 0) 
      select y; 
} 

Beispiel:

var result = ExpandLines(new[] { "+A,-A,*" }).ToList(); 

Ergebnis:

 
+A,-A,+A,-A 
+A,-A,+B,-B 
+A,-A,+C,-C 
    : 
    : 
+A,-A,+Z,-Z 

(26 Elemente)


Beispiel 2:

var result = ExpandLines(new[] { "+A,-A,*,*" }).ToList(); 

Ergebnis:

 
+A,-A,+A,-A,+A,-A 
+A,-A,+A,-A,+B,-B 
+A,-A,+A,-A,+C,-C 
     : 
     : 
+A,-A,+Z,-Z,+X,-X 
+A,-A,+Z,-Z,+Y,-Y 
+A,-A,+Z,-Z,+Z,-Z 

(676 Artikel)

+0

Wie weit hat 'var result = ExpandLines (new [] { "+ A, -A, *, *"}) ToList();.' Geben? –

+0

@El Ronnoco: Eine Liste mit 676 Artikeln. – dtb

+0

Danke für Ihre Hilfe !! – Evan

1

Hier ist ein anderes:

IEnumerable<string> ExpandWildcards(IEnumerable<string> lines) 
{ 
    return lines.SelectMany(ExpandWildcards); 
} 

IEnumerable<string> ExpandWildcards(string input) 
{ 
    string[] parts = input.Split(','); 
    var expanded = parts.Select(ExpandSingleItem); 
    return expanded.CartesianProduct().Select(line => line.JoinStrings(",")); 
} 

static readonly string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

IEnumerable<string> ExpandSingleItem(string item) 
{ 
    if (item == "*") 
     return _chars.Select(c => string.Format("+{0},-{0}", c)); 
    return new[] { item }; 
} 

static class Extensions 
{ 
    // CartesianProduct method by Eric Lippert (http://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/) 
    public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) 
    { 
     IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; 
     return sequences.Aggregate( 
      emptyProduct, 
      (accumulator, sequence) => 
      from accseq in accumulator 
      from item in sequence 
      select accseq.Concat(new[] {item}));     
    } 

    public static string JoinStrings(this IEnumerable<string> strings, string separator) 
    { 
     return strings.Aggregate(
         default(StringBuilder), 
         (sb, item) => sb == null 
          ? new StringBuilder(item) 
          : sb.Append(separator).Append(item), 
         sb => sb.ToString()); 
    } 
} 

Zugegeben, es ist ein bisschen länger als DTB-Lösung ... Aber es ist nicht rekursiv, was wichtig sein kann wenn Sie viele Artikel pro Zeile haben. Es gibt die gleichen Ergebnisse.

+0

Danke für Ihre Eingabe! – Evan

2

Eine Verallgemeinerung Ihres Problems ist die Produktion jeder Zeichenfolge, die einer bestimmten kontextfreien Grammatik entspricht. Ich habe eine neunteilige Serie darüber geschrieben, wie man so etwas in C# macht; es könnte für Sie von Interesse sein, wenn Sie komplexere Probleme in diesem Sinne haben.

http://blogs.msdn.com/b/ericlippert/archive/tags/grammars/

+0

Danke für den Link! – Evan

Verwandte Themen