Wie ändern oder Elemente aus einer enumerable Sammlung zu löschen, während durch sie in C # Iterieren

StackOverflow https://stackoverflow.com/questions/308466

  •  08-07-2019
  •  | 
  •  

Frage

Ich muss einige Zeilen aus einer Datentabelle löschen. Ich habe gehört, dass es nicht in Ordnung ist, eine Sammlung zu ändern, während durchlaufen. Anstatt also eine for-Schleife, in der ich überprüfen, ob eine Zeile, um die Anforderungen für die Löschung trifft und dann markieren Sie ihn als gelöscht, sollte ich zuerst durch die Datentabelle durchlaufen und alle Zeilen in einer Liste hinzuzufügen, iterieren dann durch die Liste und markieren die Zeilen für Löschungen. Was sind die Gründe dafür, und welche Alternativen habe ich (statt die Reihen Liste mit meine ich?).

War es hilfreich?

Lösung

Sie können Elemente aus einer Sammlung entfernen, wenn Sie eine einfache for Schleife verwenden.

Werfen Sie einen Blick auf dieses Beispiel:

        var l = new List<int>();

        l.Add(0);
        l.Add(1);
        l.Add(2);
        l.Add(3);
        l.Add(4);
        l.Add(5);
        l.Add(6);

        for (int i = 0; i < l.Count; i++)
        {
            if (l[i] % 2 == 0)
            {
                l.RemoveAt(i);
                i--;
            }
        }

        foreach (var i in l)
        {
            Console.WriteLine(i);
        }

Andere Tipps

Iterieren rückwärts durch die Liste wie ein besserer Ansatz klingt, denn wenn man ein Element und andere Elemente „fallen in die Lücke“ entfernen, die keine Rolle spielt, weil Sie bereits an diejenigen ausgesehen haben. Auch Sie müssen sich keine Sorgen über Ihre Zählvariable immer größer als die .Count.

        List<int> test = new List<int>();
        test.Add(1);
        test.Add(2);
        test.Add(3);
        test.Add(4);
        test.Add(5);
        test.Add(6);
        test.Add(7);
        test.Add(8);
        for (int i = test.Count-1; i > -1; i--)
        {
            if(someCondition){
                test.RemoveAt(i);
            }
        }

@bruno Code machen, ich würde es tun rückwärts.

Weil, wenn Sie rückwärts bewegen, der fehlende Array-Indizes nicht stört die Reihenfolge der Schleife.

var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });

for (int i = l.Count - 1; i >= 0; i--)
    if (l[i] % 2 == 0)
        l.RemoveAt(i);

foreach (var i in l)
{
    Console.WriteLine(i);
}

Aber seriuosly, in diesen Tagen, würde ich LINQ verwenden:

var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });

l.RemoveAll(n => n % 2 == 0);

Da Sie mit einem Datatable arbeiten und müssen in der Lage sein, alle Änderungen mit einem Tisch-Adapter zurück an den Server bestehen bleiben (siehe Kommentare), hier ist ein Beispiel dafür, wie Sie Zeilen löschen sollten:

DataTable dt;
// remove all rows where the last name starts with "B"
foreach (DataRow row in dt.Rows)
{
    if (row["LASTNAME"].ToString().StartsWith("B"))
    {
        // mark the row for deletion:
        row.Delete();
    }
}

Der Aufruf für die Zeilen löschen ihre RowState Eigenschaft auf Deleted ändern, aber die gelöschten Zeilen in der Tabelle verlassen. Wenn Sie immer noch mit dieser Tabelle arbeiten müssen, bevor Sie Änderungen an den Server zurück persistierende (wie wenn Sie die Tabelleninhalte minus die gelöschten Zeilen angezeigt werden sollen), müssen Sie die RowState jeder Zeile überprüfen, wie Sie so durch sie sind Iterieren :

foreach (DataRow row in dt.Rows)
{
    if (row.RowState != DataRowState.Deleted)
    {
        // this row has not been deleted - go ahead and show it
    }
}

Zeilen aus der Sammlung entfernen (wie in Brunos Antwort) den Tabellenadapter brechen, und soll in der Regel nicht mit einer Datentabelle durchgeführt werden.

Ein while-Schleife damit umgehen würde:

int i = 0;
while(i < list.Count)
{
    if(<codition for removing element met>)
    {
        list.RemoveAt(i);
    }
    else
    {
        i++;
    }
}

chakrit-Lösung kann auch verwendet werden, wenn Sie durch die Verwendung eines Delegaten .NET 2.0 (keine LINQ / Lambda-Ausdrücke) sind Targeting eher als ein Lambda-Ausdruck:

public bool IsMatch(int item) {
    return (item % 3 == 1); // put whatever condition you want here
}
public void RemoveMatching() {
    List<int> x = new List<int>();
    x.RemoveAll(new Predicate<int>(IsMatch));
}

Löschen oder zur Ergänzung der Liste, während Iterieren durch sie es brechen kann, wie Sie gesagt haben.

Früher habe ich oft zwei Listen Ansatz, das Problem zu lösen:

ArrayList matches = new ArrayList();   //second list

for MyObject obj in my_list
{

    if (obj.property == value_i_care_about)
        matches.addLast(obj);
}

//now modify

for MyObject m in matches
{
    my_list.remove(m); //use second list to delete from first list
}

//finished.

Wenn ich ein Element aus einer Sammlung entfernen muß, dass ich ich bin Aufzählen der Regel aufzählen es in umgekehrter Richtung.

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