Eine neue Funktion in C # / .NET 4.0 ist, dass Sie Ihre Aufzählung in a ändern können, foreach
ohne die Ausnahme zu erhalten. Weitere Informationen zu dieser Änderung finden Sie in Paul Jacksons Blogeintrag Ein interessanter Nebeneffekt der Parallelität: Entfernen von Elementen aus einer Sammlung während der Aufzählung .
Was ist der beste Weg, um Folgendes zu tun?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
Normalerweise benutze ich einen IList
als Cache / Puffer bis zum Ende des foreach
, aber gibt es einen besseren Weg?
c#
.net
list
enumeration
enumerable
Polo
quelle
quelle
Antworten:
Die in foreach verwendete Sammlung ist unveränderlich. Dies ist sehr beabsichtigt.
Wie es auf MSDN heißt :
Der Beitrag in dem von Poko bereitgestellten Link zeigt an, dass dies in den neuen gleichzeitigen Sammlungen zulässig ist.
quelle
Erstellen Sie eine Kopie der Aufzählung mit einer IEnumerable-Erweiterungsmethode in diesem Fall und führen Sie eine Aufzählung darüber auf. Dies würde eine Kopie jedes Elements in jeder inneren Aufzählung zu dieser Aufzählung hinzufügen.
foreach(var item in Enumerable) { foreach(var item2 in item.Enumerable.ToList()) { item.Add(item2) } }
quelle
Wie erwähnt, aber mit einem Codebeispiel:
foreach(var item in collection.ToArray()) collection.Add(new Item...);
quelle
ToArray()
) ausgeführt werden, um die Liste zu durchlaufen.Um die Antwort von Nippysaurus zu veranschaulichen: Wenn Sie die neuen Elemente zur Liste hinzufügen und auch die neu hinzugefügten Elemente während derselben Aufzählung verarbeiten möchten, können Sie nur for- Schleife anstelle von foreach- Schleife verwenden, Problem gelöst :)
var list = new List<YourData>(); ... populate the list ... //foreach (var entryToProcess in list) for (int i = 0; i < list.Count; i++) { var entryToProcess = list[i]; var resultOfProcessing = DoStuffToEntry(entryToProcess); if (... condition ...) list.Add(new YourData(...)); }
Für ein lauffähiges Beispiel:
void Main() { var list = new List<int>(); for (int i = 0; i < 10; i++) list.Add(i); //foreach (var entry in list) for (int i = 0; i < list.Count; i++) { var entry = list[i]; if (entry % 2 == 0) list.Add(entry + 1); Console.Write(entry + ", "); } Console.Write(list); }
Ausgabe des letzten Beispiels:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
Liste (15 Elemente)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
quelle
Sie können die Aufzählungssammlung während der Aufzählung nicht ändern, daher müssen Sie Ihre Änderungen vor oder nach der Aufzählung vornehmen.
Die
for
Schleife ist eine gute Alternative, aber wenn IhreIEnumerable
Sammlung nicht implementiert wirdICollection
, ist dies nicht möglich.Entweder:
1) Kopieren Sie zuerst die Sammlung. Zählen Sie die kopierte Sammlung auf und ändern Sie die ursprüngliche Sammlung während der Aufzählung. (@tvanfosson)
oder
2) Führen Sie eine Liste der Änderungen und übernehmen Sie diese nach der Aufzählung.
quelle
So können Sie das tun (schnelle und schmutzige Lösung. Wenn Sie diese Art von Verhalten wirklich benötigen, sollten Sie entweder Ihr Design überdenken oder alle
IList<T>
Mitglieder überschreiben und die Quellliste aggregieren):using System; using System.Collections.Generic; namespace ConsoleApplication3 { public class ModifiableList<T> : List<T> { private readonly IList<T> pendingAdditions = new List<T>(); private int activeEnumerators = 0; public ModifiableList(IEnumerable<T> collection) : base(collection) { } public ModifiableList() { } public new void Add(T t) { if(activeEnumerators == 0) base.Add(t); else pendingAdditions.Add(t); } public new IEnumerator<T> GetEnumerator() { ++activeEnumerators; foreach(T t in ((IList<T>)this)) yield return t; --activeEnumerators; AddRange(pendingAdditions); pendingAdditions.Clear(); } } class Program { static void Main(string[] args) { ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 }); foreach(int i in ints) ints.Add(i * 2); foreach(int i in ints) Console.WriteLine(i * 2); } } }
quelle
LINQ ist sehr effektiv zum Jonglieren mit Sammlungen.
Ihre Typen und Strukturen sind mir unklar, aber ich werde versuchen, Ihr Beispiel nach besten Kräften zu gestalten.
Aus Ihrem Code geht hervor, dass Sie für jedes Element alles aus seiner eigenen Eigenschaft 'Aufzählbar' zu diesem Element hinzufügen. Das ist sehr einfach:
foreach (var item in Enumerable) { item = item.AddRange(item.Enumerable)); }
Nehmen wir als allgemeineres Beispiel an, wir möchten eine Sammlung iterieren und Elemente entfernen, bei denen eine bestimmte Bedingung erfüllt ist. Vermeiden
foreach
, mit LINQ:Einen Artikel basierend auf jedem vorhandenen Artikel hinzufügen? Kein Problem:
myCollection = myCollection.Concat(myCollection.Select(item => new Item(item.SomeProp)));
quelle
Aus Sicht der Leistung ist es wahrscheinlich am besten, ein oder zwei Arrays zu verwenden. Kopieren Sie die Liste in ein Array, führen Sie Operationen am Array aus und erstellen Sie dann eine neue Liste aus dem Array. Der Zugriff auf ein Array-Element ist schneller als der Zugriff auf ein Listenelement. Bei Konvertierungen zwischen a
List<T>
und aT[]
kann eine schnelle "Massenkopie" -Operation verwendet werden, die den mit dem Zugriff auf einzelne Elemente verbundenen Overhead vermeidet.Angenommen, Sie haben eine
List<string>
und möchten, dass jeder Zeichenfolge in der Liste, die mit beginntT
, ein Element "Boo" folgt, während jede Zeichenfolge, die mit "U" beginnt, vollständig gelöscht wird. Ein optimaler Ansatz wäre wahrscheinlich so etwas wie:int srcPtr,destPtr; string[] arr; srcPtr = theList.Count; arr = new string[srcPtr*2]; theList.CopyTo(arr, theList.Count); // Copy into second half of the array destPtr = 0; for (; srcPtr < arr.Length; srcPtr++) { string st = arr[srcPtr]; char ch = (st ?? "!")[0]; // Get first character of string, or "!" if empty if (ch != 'U') arr[destPtr++] = st; if (ch == 'T') arr[destPtr++] = "Boo"; } if (destPtr > arr.Length/2) // More than half of dest. array is used { theList = new List<String>(arr); // Adds extra elements if (destPtr != arr.Length) theList.RemoveRange(destPtr, arr.Length-destPtr); // Chop to proper length } else { Array.Resize(ref arr, destPtr); theList = new List<String>(arr); // Adds extra elements }
Es wäre hilfreich gewesen, wenn
List<T>
eine Methode zum Erstellen einer Liste aus einem Teil eines Arrays bereitgestellt worden wäre , aber mir ist keine effiziente Methode dafür bekannt. Trotzdem sind Operationen an Arrays ziemlich schnell. Bemerkenswert ist die Tatsache, dass zum Hinzufügen und Entfernen von Elementen zur Liste kein "Verschieben" anderer Elemente erforderlich ist. Jedes Element wird direkt an die entsprechende Stelle im Array geschrieben.quelle
Sie sollten wirklich
for()
stattforeach()
in diesem Fall verwenden.quelle
Um Timos Antwort zu ergänzen, kann LINQ auch folgendermaßen verwendet werden:
items = items.Select(i => { ... //perform some logic adding / updating. return i / return new Item(); ... //To remove an item simply have logic to return null. //Then attach the Where to filter out nulls return null; ... }).Where(i => i != null);
quelle
Ich habe einen einfachen Schritt geschrieben, aber aufgrund dieser Leistung wird verschlechtert
Hier ist mein Code-Snippet: -
for (int tempReg = 0; tempReg < reg.Matches(lines).Count; tempReg++) { foreach (Match match in reg.Matches(lines)) { var aStringBuilder = new StringBuilder(lines); aStringBuilder.Insert(startIndex, match.ToString().Replace(",", " "); lines[k] = aStringBuilder.ToString(); tempReg = 0; break; } }
quelle