Laden...

Problem beim Löschen von ArrayList Einträge anhand Werten in weiterer ArrayList

Erstellt von canuck vor 17 Jahren Letzter Beitrag vor 17 Jahren 2.137 Views
C
canuck Themenstarter:in
91 Beiträge seit 2006
vor 17 Jahren
Problem beim Löschen von ArrayList Einträge anhand Werten in weiterer ArrayList

Hallo

Ich habe eine ArrayKlasse "Articles", in der Datensätze einer DB Abfrage gespeichert werden, unter anderem auch die articleID.
In einer 2. ArrayList habe ich eine Auflistung von ArticleIDs die aus dem "Articles" Array gelöscht werden müssen.

Wie kann ich diesen Vergleich und das Löschen der betreffenden Einträge im "Articles" Array möglichst Performance-optimiert umsetzen?

Ich versuche es mit:

        
        foreach (Articles articles in articlesresponse.ResultList)
        {
            // List Inhalt ArticleID an Variable zuweisen                
            int articleIDNext = articles.ArticleID;
            if (listdenied.Contains(articleIDNext))
            {                
                articlesresponse.ResultList.Remove(articles);                
            }
        }   

Ich lese also die ArticleIDs aus dem "Articles" Array aus und vergleiche ob die ID in der "listdenied" ArrayList enthalten ist. Wenn ja lösche ich den betreffenden Datensatz.

Leider kann nach dem Löschen eines Eintrages die foreach - Schleife nicht fortgesetzt werden. Es erscheint der Fehler:

"System.InvalidOperationException: Die Auflistung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden."

Wie lässt sich dieser Fehler vermeiden?
Was gibt es sonst für Möglichkeiten?

Danke für eure Hilfe

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo canuck,

Leider kann nach dem Löschen eines Eintrages die foreach - Schleife nicht fortgesetzt werden.

ja so ist das. Wenn du die Aufzählung ändern willst, musst du for verwenden.

Die schnellste Möglichkeit wird sein, die Artikel als Keys in ein Dictionary einzutragen und die ungewollten mit Remove herauszulöschen.

herbivore

3.170 Beiträge seit 2006
vor 17 Jahren

Hallo,
vielleicht klappt das:


int i = 0;
while (i<response.ResultList.Length)
{
Articles a = response.ResultList[i];
if(/*remove*/)
{
response.ResultList.RemoveAt[i];
}
else
{
  i++;
}
}

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

2.082 Beiträge seit 2005
vor 17 Jahren

Hallo MarsStein,

das wage ich zu bezweifeln, da Arrays nicht dynamisch sind. Du meinst wahrscheinlich ArrayList. Da gibts das Add und Remove.

Bei Arrays kannst du höchstens einen "null"-Wert definieren.

Beispiel Element 3 von Array auf null setzen:

//Array erstellen
int[] positiveIntegers = int[10];

//Array füllen
for(int i = 0; i < positiveIntegers.Length; i++) {
     positiveIntegers[i] = i+1;
}

//Element an Stelle 3 löschen
positiveIntegers[2] = -1;

//Array auslesen
for(int i = 0; i < positiveIntegers.Length; i++) {
     if(positiveIntegers[i] != -1) {
          Console.WriteLine("Element an Stelle "+(i+1).ToString()+" ist nicht leer.");
     }
}

Es ist toll jemand zu sein, der nichts von der persönlichen Meinung Anderer hält. - frisch-live.de

C
canuck Themenstarter:in
91 Beiträge seit 2006
vor 17 Jahren

Sorry, ich habe mich wohl zuwenig klar ausgedrückt.

Es sind beides ArrayLists, bei der "Articles" Liste ist zusätzlich eine Klasse dahinter die die einzelnen Listenelemente vorgibt. Habe den Titel meines Threads noch angepasst.

Es funktioniert jetzt mit:


        int i = 0;
        while (i<articlesresponse.ResultList.Count)
        {
            Articles articles = articlesresponse.ResultList[i];
            int articleIDNext = articles.ArticleID;
            if (listdenied.Contains(articleIDNext))
            {
                articlesresponse.ResultList.Remove(articles);
            }
            else
            {
                i++;
            }
        }

Jedenfalls löscht es mir nun die gewünschten Einträge heraus.
Ich denke, das ist der richtige Weg, oder gibt es noch einen performanteren?

Danke für die Hilfe und Gruss

3.170 Beiträge seit 2006
vor 17 Jahren

@frisch
Das ist mir schon klar, aber im Beispielquelltext

Original von canuck
if (listdenied.Contains(articleIDNext))
{
articlesresponse.ResultList.Remove(articles);
}

Daher bin ich von einem Objekt ausgegangen, das die Methode unterstützt.

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

175 Beiträge seit 2006
vor 17 Jahren

Evtl. eleganter ist es, die Iteration der ArrayList vom letzten Element her zu beginnen - so stellst du sicher, dass keine Elemente die noch vor dem aktuellen Iterator-Wert liegen, geändert werden.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo canuck,

Ich denke, das ist der richtige Weg, oder gibt es noch einen performanteren?

ich habe ja schon den Weg genannt, den ich für am performantesten halte.

herbivore

C
canuck Themenstarter:in
91 Beiträge seit 2006
vor 17 Jahren

@ dani.net

meinst du so?


        int i = articlesresponse.ResultList.Count;        
        while (i>0)
        {
            Articles articles = articlesresponse.ResultList[i];
            int articleIDNext = articles.ArticleID;
            if (listdenied.Contains(articleIDNext))
            {
                articlesresponse.ResultList.Remove(articles);
            }
            else
            {
                i--;
            }
        }   

So erscheint der Fehler:

System.ArgumentOutOfRangeException: Der Index lag ausserhalb des Bereichs. Er muss nicht negativ und kleiner als die Auflistung sein.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo canuck,

ich sehe da kein Dictionary. 🙂

herbivore

3.170 Beiträge seit 2006
vor 17 Jahren

Canuck, wenn du's sorum machen willst, darf das i-- nicht im else sztehen, sondern muss immer gemacht werden.

Und ausserdem den Iterator mit Count-1 initialisieren und auf ≥0 testen

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo canuck,

mein Vorschlag ist beschrieben in Grundlegendes zu Hashtables (Dictionaries) in dem Abschnitt, wo es um "Allerweltsworte" geht, wenn man continue durch Remove ersetzt.

Das eigentlich Löschen geht dann so:


Dictionary <String, Article> dictResult;
List <String> listDenied;
//...
foreach (String strArticleID in listDenied) {
   dictResult.Remove (strArticleID);
}

herbivore

C
canuck Themenstarter:in
91 Beiträge seit 2006
vor 17 Jahren

@MarsStein: Danke, so hat es geklappt

@herbivore: Ich werde mir das anschauen und den Check bei Gelegenheit noch anpassen, ebenfalls danke für deine Hilfe