Frage

Ich möchte eine Liste in C # generieren. Ich vermisse Python Listenkomprehensionen. Gibt es eine C # Art und Weise Sammlungen on the fly wie Listenkomprehensionen und Generator Ausdrücke in Python Sie zu erstellen?

War es hilfreich?

Lösung

Wenn Sie C # 3.0 (VS2008) verwenden, dann LINQ to Objects können sehr ähnliche Dinge tun:

List<Foo> fooList = new List<Foo>();
IEnumerable<Foo> extract = from foo in fooList where foo.Bar > 10 select Foo.Name.ToUpper();

Andere Tipps

Matt hat Abfrage-Ausdrücken erwähnt. Diese sind für LINQ im Allgemeinen, nebenbei gesagt - nicht nur LINQ to Objects. (Zum Beispiel der gleiche Abfrage auf einen LINQ to SQL angewandt Datacontext würde die Filter und Projektion auf der Datenbank auszuführen.)

Die Abfrageausdrücke in C # 3 ist einfach syntaktischer Zucker über normalen C # Code zu schreiben - obwohl Abfrageausdrücke in der Regel rief am Ende Erweiterungsmethoden . (Sie haben nicht zu, und der Compiler kümmert sich nicht darum, sondern sie in der Regel.) Es gibt verschiedene Dinge, die Sie mit Kollektionen tun können, die in Ausdrücken C # Abfrage nicht verfügbar sind, die aber durch Methodenaufrufe unterstützt werden, so es lohnt sich bewusst, beide Arten von Syntax zu sein. Zum Beispiel Matts Abfrage Ausdruck:

List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = from foo in fooList where foo.Bar > 10 select foo.Name.ToUpper();

wird "vorverarbeitet" in:

List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where(foo => foo.Bar > 10)
                                     .Select(foo => foo.Name.ToUpper());

Wenn Sie wollen (sagen wir) Filter basierend auf dem Index des Wertes in der ursprünglichen Sammlung, können Sie eine entsprechende Überlastung Wo die über Abfrageausdrücke nicht verfügbar ist:

List<Foo> fooList = new List<Foo>();
IEnumerable<string> extract = fooList.Where((foo, index) => foo.Bar > 10 + index)
                                     .Select(foo => foo.Name.ToUpper());

Oder man könnte die Länge des längsten Namen Anpassung der Kriterien finden:

List<Foo> fooList = new List<Foo>();
int longestName = fooList.Where((foo, index) => foo.Bar > 10 + index)
                         .Select(foo => foo.Name)
                         .Max();

(Sie müssen nicht Haben die Projektion und max in getrennten Verfahren zu tun -. Gibt es eine Max Überlastung, die auch einen Vorsprung nimmt)

Mein Punkt ist, dass Methoden Erweiterung, die Sie sehr leicht anspruchsvolle Abfragen aufbauen können.

Sie erwähnen Python-Generatoren als auch - C # diese in Form von Iterator Blöcke hat. Tatsächlich sind diese unglaublich nützlich, wenn LINQ-Ähnliche Operatoren zu implementieren. (Da die meisten von LINQ to Objects auf Erweiterungsmethoden basiert, können Sie Ihre eigenen Operatoren hinzufügen, die „native“ zu LINQ aussehen -. Sie können sie aber nicht die Abfrage Ausdruck selbst Syntax ändern kann)

List<T>.ConvertAll verhält sich wie Listenkomprehensionen durch die gleiche Operation an jedes Element auf einer bestehenden Liste und dann eine neue Kollektion zurück. Dies ist eine Alternative zur Verwendung von Linq vor allem, wenn Sie noch .NET verwenden 2.0.

In Python, ein einfaches Liste Verständnis Beispiel:

>>> foo = [1, 2, 3]
>>> bar = [x * 2 for x in foo]
>>> bar
[2, 4, 6]

Für C # 3.0 können Sie eine Lambda-Funktion übergeben Angabe, welche Art von Mapping-Funktion benötigt wird.

public static void Main()
{
    var foo = new List<int>{ 1, 2, 3};
    var bar = foo.ConvertAll(x => x * 2);    // list comprehension

    foreach (var x in bar)
    {
        Console.WriteLine(x);  // should print 2 4 6
    }
}

Für C # 2.0 können Sie eine anonyme Methode mit dem Converter Delegierten verwenden das Äquivalent auszuführen.

public static void Main()
{
    List<int> foo = new List<int>(new int[]{ 1, 2, 3});
    List<int> bar = foo.ConvertAll(new Converter<int, int>(delegate(int x){ return x * 2; }));  // list comprehension

    foreach (int x in bar)
    {
        Console.WriteLine(x);  // should print 2 4 6
    }
}

(Hinweis: das gleiche kann mit Arrays durchgeführt wird unter Verwendung von Array.ConvertAll

Es gibt diese:

new List<FooBar> { new Foo(), new Bar() }

, die nur ein wenig länger als sein Python entspricht:

[Foo(), Bar()]

Und dann gibt es diese:

public IEnumerable<FooBar> myFooBarGenerator() {
     yield return new Foo();
     yield return new Bar();
}

das ist der Python-Äquivalent:

def myFooBarGenerator():
    yield Foo()
    yield Bar()

Ich weiß, das ist sehr, sehr spät eine Antwort, aber ich auch gefragt, ob C # etwas äquivalent zu Pythons Liste Verständnis hat. Antworten von beiden Matt Campbell und Jon Skeet zeigen, wie man extrahiert eine Liste aus einem anderen bestehenden, soweit ich das verstanden. Aber eine Liste Verständnis der Python kann auch eine Liste von Grund auf neu erstellen. Also hier ist, was ich kam mit.

Zuerst werde ich das Python-Liste Verständnis zeigen und dann äquivalent seiner C #, die ich kam mit.

Das Spielzeug Aufgabe ist es, eine Zeichenfolge wie folgt erstellen

cb01, cb02, cb02, ... , cb50

Python Liste Verständnis:

s = ', '.join('cb{0:02}'.format(i+1) for i in range(50))

C # -Äquivalent kam ich mit bis:

string s = String.Join(", ", new Func<List<string>>( () =>
{
    List<string> list = new List<string>();
    foreach (int i in Enumerable.Range(1, 50))
        list.Add(String.Format("cb{0:00}", i));

    return list;
}).Invoke());

Ich bin nicht sicher, ob ich über tat nichts oder nicht though.


Edit: (von dem, was Jon Skeet in seinem Kommentar erwähnt, ein echter Einzeiler entspricht Python Liste Verständnis)

String.Join(", ", Enumerable.Range(1, 50).Select(x => $"cb{x:00}")))

Beachten Sie, dass $ Sache ist ein C # 6 Funktion . Wenn Sie noch nicht C # 6 verwenden, können Sie mit dem alten String.Format() Weg gehen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top