Array versus List : Wann welche verwenden?

MyClass[] array; List list; 

In welchen Szenarien ist man dem anderen vorzuziehen? Und warum?

   

In Wirklichkeit ist es selten, dass Sie ein Array verwenden möchten. Verwenden Sie eine List unbedingt immer dann, wenn Sie Daten hinzufügen / entfernen möchten, da das Ändern der Größe von Arrays teuer ist. Wenn Sie wissen, dass die Daten eine feste Länge haben und Sie aus einem ganz bestimmten Grund (nach dem Benchmarking) eine Mikrooptimierung durchführen möchten, kann ein Array nützlich sein.

List bietet viel mehr functionalität als ein Array (obwohl LINQ es etwas aufpoliert) und ist fast immer die richtige Wahl. Außer params Argumente. ;-p

Als Zähler – List ist eindimensional; where-wie Sie rechteckige (etc) -Arrays wie int[,] oder string[,,] – aber es gibt andere Möglichkeiten der Modellierung solcher Daten (wenn Sie brauchen) in einem Objektmodell.

Siehe auch:

  • Wie / wann die Verwendung von Arrays in c # .net aufzugeben?
  • Arrays, Was ist der Sinn?

In meinem protobuf-net- Projekt nutze ich daher Arrays. ganz auf performance:

  • es macht eine Menge Bit-Verschiebung, so dass ein byte[] ziemlich wesentlich für die Kodierung ist;
  • Ich benutze einen lokalen rolling byte[] Puffer, den ich vor dem Senden an den darunterliegenden Stream (und vv) fülle; schneller als BufferedStream etc;
  • Es verwendet intern ein Array-basiertes Modell von Objekten ( Foo[] anstelle von List ), da die Größe nach dem Erstellen fest ist und sehr schnell sein muss.

Aber das ist definitiv eine Ausnahme; Bei der allgemeinen Geschäftsabwicklung gewinnt eine List jedes Mal.

Wirklich nur zu antworten, um einen Link hinzuzufügen, den ich überrascht habe, wurde noch nicht erwähnt: Erics Lipperts Blogeintrag auf “Arrays, die als etwas schädlich angesehen werden.”

Sie können anhand des Titels feststellen, dass die Verwendung von Sammlungen empfohlen wird, wo immer es praktikabel ist – aber wie Marc zu Recht betont, gibt es viele Orte, an denen ein Array wirklich die einzige praktische Lösung ist.

Verwenden Sie ein Array, wenn Sie mit Daten arbeiten, die:

  • in der Größe fixiert oder unwahrscheinlich viel zu wachsen
  • geeignet groß (mehr als 10, 50, 100 Elemente, abhängig vom Algorithmus)
  • Sie werden viel Indexierung darin machen, dh Sie wissen, dass Sie häufig das dritte Element oder das fünfte oder was auch immer wollen.

Verwenden Sie eine Liste für:

  • Datenlisten variabler Länge
  • Diese werden meist als Stack oder Queue verwendet oder müssen komplett iteriert werden
  • Wenn Sie keinen Ausdruck schreiben möchten, um die ultimative Array-Größe für die Deklaration abzuleiten, und Sie nicht verschwenderisch eine große Zahl auswählen möchten

Verwenden Sie eine Hashmap für:

  • Datenlisten variabler Länge
  • Das müsste wie ein Array indiziert werden

In Wirklichkeit wirst du fast immer eine Liste oder Hashmaps haben wollen. Wenn du das nächste Mal eine Datenstruktur auswählst, denke darüber nach, was es für dich (oder deinen Code) gut machen muss. Wählen Sie dann etwas daraus. Wählen Sie im Zweifelsfall etwas möglichst allgemeines, dh eine Schnittstelle, an der Sie die Implementierung relativ einfach ablösen können. Einige gute Links in den anderen Antworten.

Ungeachtet der anderen Antworten, die List empfehlen, sollten Sie bei der Verarbeitung Arrays verwenden:

  • Bild-Bitmap-Daten
  • andere Low-Level-Datenstrukturen (zB Netzwerkprotokolle)

Es sei denn, Sie sind wirklich mit der performance beschäftigt, und damit meine ich: “Warum verwenden Sie .Net statt C ++?” Sie sollten bei List <> bleiben. Es ist einfacher zu warten und macht die ganze dreckige Arbeit der Größenänderung eines Arrays hinter den Kulissen für Sie. (Falls erforderlich, ist List <> ziemlich schlau, wenn es um die Auswahl von Array-Größen geht, die es normalerweise nicht benötigt.)

Arrays sollten gegenüber List verwendet werden, wenn die Unveränderbarkeit der Sammlung selbst Teil des Vertrags zwischen dem Client- und Provider-Code ist (nicht unbedingt Unveränderbarkeit der Elemente innerhalb der Sammlung) und wenn IEnumerable nicht geeignet ist.

Beispielsweise,

 var str = "This is a string"; var strChars = str.ToCharArray(); // returns array 

Es ist klar, dass die Modifikation von “strChars” das ursprüngliche “str” ​​-Objekt nicht mutieren wird, unabhängig von der Kenntnis der Implementierung des “str” ​​zugrundeliegenden Typs.

Aber stell dir das vor

 var str = "This is a string"; var strChars = str.ToCharList(); // returns List strChars.Insert(0, 'X'); 

In diesem Fall ist es aus diesem Codeschnipsel allein nicht klar, ob die Einfügemethode das ursprüngliche “str” ​​-Objekt mutieren wird oder nicht. Um diese Entscheidung treffen zu können, benötigt man Kenntnis von String auf Implementierungsebene, was den Ansatz “Entwurf nach Vertrag” unterbricht. Im Falle von String ist das keine große Sache, aber in fast jedem anderen Fall kann es eine große Sache sein. Das Festlegen der Liste auf schreibgeschützt führt jedoch zu Laufzeiterrorsn und nicht zur Kompilierungszeit.

Wenn ich genau weiß, wie viele Elemente ich brauche, sagen wir, ich brauche 5 Elemente und nur 5 Elemente, dann benutze ich ein Array. Ansonsten benutze ich nur eine Liste .

In den meisten List würde die Verwendung einer List ausreichen. Eine List verwendet ein internes Array zum Verarbeiten ihrer Daten und passt die Größe des Arrays automatisch an, wenn mehr Elemente zur List hinzugefügt werden als die aktuelle Kapazität. Dies macht die Verwendung einfacher als bei einem Array, bei dem die Kapazität vorher bekannt sein muss.

Weitere Informationen zu Listen in C # finden Sie unter http://msdn.microsoft.com/en-us/library/ms379570(v=vs.80).aspx#datastructures20_1_topic5 oder dekompilieren Sie einfach System.Collections.Generic.List .

Wenn Sie mehrdimensionale Daten benötigen (zum Beispiel mit einer Matrix oder in der Grafikprogrammierung), würden Sie wahrscheinlich stattdessen mit einem array gehen.

Wie immer, wenn Speicher oder performance ein Problem ist, messen Sie es! Andernfalls könnten Sie falsche Annahmen über den Code treffen.

Eine weitere Situation, die noch nicht erwähnt wurde, ist, wenn man eine große Anzahl von Elementen hat, von denen jedes aus einer festen Menge von zusammenhängenden aber unabhängigen Variablen besteht, die zusammengeklebt sind (zB die Koordinaten eines Punktes oder die Eckpunkte eines 3d Dreiecks). Ein Array von Strukturen mit exponierten Feldern erlaubt es, seine Elemente effizient “an Ort und Stelle” zu verändern – etwas, das mit keinem anderen Sammlungstyp möglich ist. Da ein Array von Strukturen seine Elemente nacheinander im RAM hält, können sequentielle Zugriffe auf Array-Elemente sehr schnell sein. In Situationen, in denen Code viele aufeinanderfolgende Durchgänge durch ein Array durchführen muss, kann ein Array von Strukturen ein Array oder eine andere Sammlung von classnobjektverweisen um einen Faktor von 2: 1 excel. Des Weiteren kann die Fähigkeit, Elemente an Ort und Stelle zu aktualisieren, einem Array von Strukturen ermöglichen, jede andere Art von Sammlung von Strukturen zu excel.

Obwohl Arrays nicht in der Größe veränderbar sind, ist es nicht schwierig, einen Array-Verweis zusammen mit der Anzahl der verwendeten Elemente im Code zu speichern und das Array je nach Bedarf durch ein größeres zu ersetzen. Alternativ könnte man einfach Code für einen Typ schreiben, der sich ähnlich wie ein List MyPoints.Add(nextPoint); aber seinen Backing-Speicher MyPoints.Add(nextPoint); , so dass man entweder MyPoints.Add(nextPoint); sagen MyPoints.Add(nextPoint); oder MyPoints.Items[23].X += 5; . Beachten Sie, dass Letzteres nicht unbedingt eine Ausnahme austriggers, wenn Code versucht, über das Ende der Liste hinaus zuzugreifen, aber die Verwendung wäre ansonsten konzeptionell sehr ähnlich zu List .

Listen in .NET sind Wrapper über Arrays und verwenden intern ein Array. Die zeitliche Komplexität von Operationen auf Listen ist die gleiche wie bei Arrays, allerdings gibt es ein wenig mehr Overhead mit der gesamten hinzugefügten functionalität / Benutzerfreundlichkeit von Listen (wie automatische Größenänderung und die Methoden, die mit der List-class geliefert werden). Ziemlich genau würde ich empfehlen, Listen in allen Fällen zu verwenden, es sei denn, es gibt einen zwingenden Grund, dies nicht zu tun, etwa wenn Sie extrem optimierten Code schreiben müssen oder mit anderem Code arbeiten, der um Arrays herum aufgebaut ist.

Es hängt vollständig von den Kontexten ab, in denen die Datenstruktur benötigt wird. Wenn Sie beispielsweise Elemente erstellen, die von anderen functionen oder Diensten verwendet werden sollen, verwenden Sie List, um diese zu erreichen.

Wenn Sie jetzt eine Liste von Elementen haben und diese nur anzeigen möchten, sagen Sie in einem Webseiten-Array, welchen Container Sie verwenden sollen.

Anstatt einen Vergleich der Merkmale jedes Datentyps durchzuführen, denke ich, ist die pragmatischste Antwort: “Die Unterschiede sind wahrscheinlich nicht so wichtig für das, was Sie erreichen müssen, zumal sie IEnumerable implementieren, also folgen Sie gängigen Konventionen und Anwendungen Eine List bis Sie einen Grund haben, dies nicht zu tun. An diesem Punkt haben Sie wahrscheinlich einen Grund, ein Array über eine List . ”

Die meiste Zeit in verwaltetem Code werden Sie Collections bevorzugen, die so leicht zu bearbeiten sind wie möglich, anstatt sich um Mikrooptimierungen zu sorgen.

Da keiner erwähnt: MyClass[] und List implementieren beide IList . Wenn Sie darüber nachdenken, welches Argument Sie als Argument akzeptieren IList , können Sie es als IList für die Bequemlichkeit der Anrufer deklarieren. (zB Foo(IList foo) kann wie Foo(new[] { 1, 2, 3 }) oder Foo(new List { 1, 2, 3 }) aufgerufen werden)

Sie mögen unpopulär sein, aber ich bin ein Fan von Arrays in Spielprojekten. – Iterationsgeschwindigkeit kann in einigen Fällen wichtig sein, foreach auf einem Array hat erheblich weniger Overhead, wenn Sie nicht viel pro Element tun – Hinzufügen und Entfernen ist nicht so schwer mit Hilfsfunktionen – Es ist langsamer, aber in Fällen, in denen Sie es nur einmal erstellen Es spielt keine Rolle – In den meisten Fällen wird weniger zusätzlicher Speicher verschwendet (nur wirklich wichtig bei Arrays von Strukturen) – Etwas weniger Müll und pointers und pointers jagen

Allerdings verwende ich List häufiger als Arrays in der Praxis, aber sie haben jeweils ihren Platz.

Es wäre schön, wenn List einen eingebauten Typ hätte, um den Wrapper- und Enumerations-Overhead zu optimieren.