.NET bietet einen generischen Listencontainer, dessen Leistung nahezu identisch ist (siehe Frage Leistung von Arrays vs. Listen). Sie unterscheiden sich jedoch in der Initialisierung erheblich.
Arrays lassen sich sehr einfach mit einem Standardwert initialisieren und haben per Definition bereits eine bestimmte Größe:
string[] Ar = new string[10];
So kann man sicher zufällige Elemente zuweisen, sagen wir:
Ar[5]="hello";
mit Liste sind die Dinge schwieriger. Ich kann zwei Möglichkeiten sehen, um dieselbe Initialisierung durchzuführen, von denen Sie keine als elegant bezeichnen würden:
List<string> L = new List<string>(10);
for (int i=0;i<10;i++) L.Add(null);
oder
string[] Ar = new string[10];
List<string> L = new List<string>(Ar);
Was wäre ein sauberer Weg?
BEARBEITEN: Die bisherigen Antworten beziehen sich auf die Kapazität, die etwas anderes ist als das Vorabfüllen einer Liste. Bei einer Liste, die gerade mit einer Kapazität von 10 erstellt wurde, ist dies beispielsweise nicht möglichL[2]="somevalue"
EDIT 2: Die Leute fragen sich, warum ich Listen auf diese Weise verwenden möchte, da dies nicht die Art ist, wie sie verwendet werden sollen. Ich kann zwei Gründe sehen:
Man könnte ziemlich überzeugend argumentieren, dass Listen die Arrays der "nächsten Generation" sind, die Flexibilität ohne Strafe hinzufügen. Daher sollte man sie standardmäßig verwenden. Ich weise darauf hin, dass sie möglicherweise nicht so einfach zu initialisieren sind.
Was ich gerade schreibe, ist eine Basisklasse, die Standardfunktionen als Teil eines größeren Frameworks bietet. In der von mir angebotenen Standardfunktionalität ist die Größe der Liste in Advanced bekannt, weshalb ich ein Array hätte verwenden können. Ich möchte jedoch jeder Basisklasse die Möglichkeit bieten, sie dynamisch zu erweitern, und entscheide mich daher für eine Liste.
List
ist kein Ersatz fürArray
. Sie lösen deutlich getrennte Probleme. Wenn Sie eine feste Größe wünschen, möchten Sie eineArray
. Wenn Sie a verwendenList
, machen Sie es falsch.Antworten:
Ich kann nicht sagen, dass ich das sehr oft brauche - könnten Sie mehr Details darüber geben, warum Sie das wollen? Ich würde es wahrscheinlich als statische Methode in eine Hilfsklasse einfügen:
Sie könnten verwenden,
Enumerable.Repeat(default(T), count).ToList()
aber das wäre aufgrund der Puffergrößenänderung ineffizient.Wenn
T
es sich um einen Referenztyp handelt, werdencount
Kopien der für denvalue
Parameter übergebenen Referenz gespeichert, sodass alle auf dasselbe Objekt verweisen. Das kann je nach Anwendungsfall das sein, was Sie wollen oder nicht.BEARBEITEN: Wie in den Kommentaren erwähnt, können Sie
Repeated
die Liste mit einer Schleife füllen, wenn Sie möchten. Das wäre auch etwas schneller. Persönlich finde ich den CodeRepeat
beschreibender und vermute, dass in der realen Welt der Leistungsunterschied irrelevant wäre, aber Ihr Kilometerstand kann variieren.quelle
Enumerable.Repeat(...).ToArray()
, das ist nicht , wie ich es bin mit.Enumerable.Repeat()
das folgendermaßen verwendet (Pair
genau wie das C ++ - Äquivalent implementiert ): AlsEnumerable.Repeat( new Pair<int,int>(int.MaxValue,-1), costs.Count)
ich den Nebeneffekt bemerkte, war dasList
voll von Kopien, auf die für ein einzelnes Objekt verwiesen wurde. Durch Ändern eines Elements wirdmyList[i].First = 1
jedes einzelne Element im Ganzen geändertList
. Ich habe Stunden gebraucht, um diesen Fehler zu finden. Kennt ihr eine Lösung für dieses Problem (außer nur eine gemeinsame Schleife zu verwenden und zu verwenden.Add(new Pair...)
?quelle
L
einfach den Speicher vonstring[10]
as is wiederverwendet (der Sicherungsspeicher einer Liste ist auch ein Array) oder einen eigenen neuen Speicher zuweist und dann den Inhalt von kopiertstring[10]
.string[10]
wird automatisch Müll gesammelt, wennL
die spätere Route ausgewählt wird.Verwenden Sie den Konstruktor, der ein int ("Kapazität") als Argument verwendet:
EDIT: Ich sollte hinzufügen, dass ich Frederik zustimme. Sie verwenden die Liste auf eine Weise, die gegen die gesamte Begründung verstößt, die dahinter steckt.
EDIT2:
Warum sollte jemand die Größe einer Liste mit allen Nullwerten kennen müssen? Wenn die Liste keine realen Werte enthält, würde ich eine Länge von 0 erwarten. Die Tatsache, dass dies ungeschickt ist, zeigt jedenfalls, dass dies gegen die beabsichtigte Verwendung der Klasse verstößt.
quelle
new List<string>()
das Problem nicht unterscheidet . Gut gemacht,list[index] = obj;
füllen als auch einige andere Listenfunktionen verwenden.Erstellen Sie zuerst ein Array mit der Anzahl der gewünschten Elemente und konvertieren Sie das Array dann in eine Liste.
quelle
Warum verwenden Sie eine Liste, wenn Sie sie mit einem festen Wert initialisieren möchten? Ich kann verstehen, dass Sie aus Gründen der Leistung eine anfängliche Kapazität haben möchten, aber ist dies nicht einer der Vorteile einer Liste gegenüber einem regulären Array, das bei Bedarf erweitert werden kann?
Wenn Sie dies tun:
Sie erstellen eine Liste mit einer Kapazität von 100 Ganzzahlen. Dies bedeutet, dass Ihre Liste erst wachsen muss, wenn Sie das 101. Element hinzufügen. Das zugrunde liegende Array der Liste wird mit einer Länge von 100 initialisiert.
quelle
Das Initialisieren des Inhalts einer solchen Liste ist nicht wirklich das, wofür Listen gedacht sind. Listen dienen zur Aufnahme von Objekten. Wenn Sie bestimmten Objekten bestimmte Zahlen zuordnen möchten, sollten Sie anstelle einer Liste eine Schlüssel-Wert-Paar-Struktur wie eine Hash-Tabelle oder ein Wörterbuch verwenden.
quelle
Sie scheinen die Notwendigkeit einer Positionszuordnung zu Ihren Daten zu betonen. Wäre ein assoziatives Array also nicht passender?
quelle
Wenn Sie die Liste mit N Elementen eines festen Werts initialisieren möchten:
quelle
Mit Linq können Sie Ihre Liste geschickt mit einem Standardwert initialisieren. (Ähnlich wie die Antwort von David B. )
Gehen Sie einen Schritt weiter und initialisieren Sie jede Zeichenfolge mit unterschiedlichen Werten: "Zeichenfolge 1", "Zeichenfolge 2", "Zeichenfolge 3" usw.:
quelle
quelle
Die akzeptierte Antwort (die mit dem grünen Häkchen) weist ein Problem auf.
Das Problem:
Ich empfehle, die obige Zeile zu ändern, um eine Kopie des Objekts zu erstellen. Es gibt viele verschiedene Artikel darüber:
Wenn Sie jedes Element in Ihrer Liste mit dem Standardkonstruktor und nicht mit NULL initialisieren möchten, fügen Sie die folgende Methode hinzu:
quelle
Ein Hinweis zu IList: MSDN IList Anmerkungen : "IList-Implementierungen lassen sich in drei Kategorien einteilen: schreibgeschützt, feste Größe und variable Größe. (...). Die generische Version dieser Schnittstelle finden Sie unter
System.Collections.Generic.IList<T>
."IList<T>
erbt NICHT vonIList
(List<T>
implementiert aber beideIList<T>
undIList
), hat aber immer eine variable Größe . Seit .NET 4.5 haben wir aber auchIReadOnlyList<T>
AFAIK, es gibt keine generische Liste mit fester Größe, nach der Sie suchen würden.quelle
Dies ist ein Beispiel, das ich für meinen Unit-Test verwendet habe. Ich habe eine Liste von Klassenobjekten erstellt. Dann habe ich forloop verwendet, um die 'X'-Anzahl von Objekten hinzuzufügen, die ich vom Dienst erwarte. Auf diese Weise können Sie eine Liste für eine bestimmte Größe hinzufügen / initialisieren.
Ich hoffe, ich habe euch geholfen.
quelle
Ein bisschen spät, aber die erste Lösung, die Sie vorgeschlagen haben, scheint mir viel sauberer zu sein: Sie weisen den Speicher nicht zweimal zu. Sogar List Constrcutor muss das Array durchlaufen, um es zu kopieren. es weiß nicht einmal im Voraus, dass nur Nullelemente darin sind.
1. - N zuordnen - Schleife N Kosten: 1 * Zuweisen (N) + N * Schleifen_iteration
2. - N zuweisen - N + loop () zuweisen Kosten: 2 * (N) + N * loop_iteration zuweisen
Die Zuweisung von List und Loops in List kann jedoch schneller sein, da List eine integrierte Klasse ist, aber C # sooo jit-kompiliert ist ...
quelle