2009-10-07 10 views
23

Tak, mam problem, aby usunąćUsuwanie XElements w pętli foreach

foreach (XElement x in items.Elements("x")) 
{ 
    XElement result = webservice.method(x); 

    if (/*condition based on values in result*/) 
    { 
     x.Remove(); 
    } 
} 

Problemem jest to, że wywołanie x.Remove() zmienia foreach tak, że jeśli istnieją dwa elementy („X”), a pierwsza jest usunięta, pętla nie dostaje się do drugiego elementu x.

Jak mam to zapętlić? Czy powinno to być przepisane w inny sposób?

+8

I rzeczywiście właśnie zmodyfikował foreach do bycia „foreach (Xelement xw items.Elements (” x „). Rewers())”, a który wydaje się działać dobrze jak przed problemem był foreach przeniósł indeksuj w górę, a funkcja Usuń usuwa wszystko, powodując pominięcie elementów. Odwrócenie zamówienia wydaje się mieć sens. Ale zostawię pytanie otwarte na wypadek, gdyby ktoś miał lepsze rozwiązanie. – CaffGeek

+0

Zrobiłem pętlę for, gdzie musiałem zrobić i-- jeśli rzeczywiście usunięto element, aby zrekompensować indeks. Twoja droga z odwrotnością nie wydaje się złą opcją, ale nie jestem ekspertem od technologii .NET, więc jestem trochę sceptycznie nastawiona do tego, co mówię, lol. – Xaisoft

+0

poprawiony do C# 3.0. Nie ma C# z wersją 3.5 (zobacz ten post dla szczegółów http://stackoverflow.com/questions/247621/what-are-t--correct-version-numbers-for-c) – Vaccano

Odpowiedz

30

Podejrzewam, że Linq może ci w tym pomóc.

using System.Linq; 

void foo() 
{ 
    items.Elements("x") 
     .Where(x => condition(webservice.method(x))) 
     .Remove(); 
} 

Jeśli to nie zadziała (czyli wewnętrzny moduł wyliczający jest nadal unieważnione) sprawiają, że płytki kopię wybranych elementów i usunąć je w następujący sposób.

using System.Linq; 

void foo() 
{ 
    List xElements = items.Elements("x") 
          .Where(x => condition(webservice.method(x))) 
          .ToList(); 

    for (int i = xElements.Count - 1; i > -1; i--) 
    { 
     xElements[i].Remove(); 
    } 
} 
+0

+1 Idealna sytuacja, jeśli używasz .Net 3.5 –

+0

Pierwszy fragment kodu pracował dla mnie. Świetne rozwiązanie. +1 –

+0

Zauważ, że każdy Remove() przechodzi wewnętrznie połączoną listę elementów potomnych od pierwszego potomka, a zatem złożoność obliczeniowa każdego usunięcia to O (N). Czy istnieje sposób usunięcia elementów (O)? – redcalx

1

Utwórz kolekcję przed logiką pętli, dodaj elementy do usunięcia do nowej kolekcji, a następnie wywołaj elementy. Usuń wszystkie elementy z nowej kolekcji.

+0

To powinno zadziałać. Pamiętam, jak to robiłem. Moja odpowiedź prawdopodobnie nie jest dobra. Pamiętam coś o tym, że jeśli zmienisz listę lub coś w tym stylu, dobrym pomysłem jest użycie, ale jeśli po prostu przepływasz bez wprowadzania jakichkolwiek zmian, foreach jest w porządku. Czy to jest poprawne? – Xaisoft