문제

나는 코드가있다 원하다 이렇게 보이도록 :

List<Type> Os;

...

foreach (Type o in Os)
    if (o.cond)
        return;  // Quitting early is important for my case!
    else
        Os.Remove(o);

... // Other code

내부에있을 때 목록에서 제거 할 수 없기 때문에 이것은 작동하지 않습니다. foreach 해당 목록을 통한 루프 :

문제를 해결하는 일반적인 방법이 있습니까?

필요한 경우 다른 유형으로 전환 할 수 있습니다.

Option 2:

List<Type> Os;

...

while (Os.Count != 0)
     if (Os[0].cond)
         return;
     else
         Os.RemoveAt(0);

... // Other code

추악하지만 작동해야합니다.

도움이 되었습니까?

해결책

당신은 정말로 이것을해야합니까? foreach 고리?

이렇게하면 예제와 동일한 결과, 즉 조건과 일치하는 첫 번째 항목까지 목록에서 모든 항목을 제거하거나 조건과 일치하지 않으면 모든 항목을 제거합니다.

int index = Os.FindIndex(x => x.cond);

if (index > 0)
    Os.RemoveRange(0, index);
else if (index == -1)
    Os.Clear();

다른 팁

목록을 거꾸로 반복 할 수 있습니다.

for (int i = myList.Count - 1; i >= 0; i--)
{
    if (whatever) myList.RemoveAt(i);
}

제거하지 않는 항목을 찾을 때 종료하려는 것에 대한 의견에 대한 응답으로 While Loop을 사용하는 것이 최상의 솔루션이됩니다.

Foreach 루프 내부에서 반복하는 컬렉션에서 아무것도 제거해서는 안됩니다. 기본적으로 당신이 앉아있는 가지를 보는 것과 같습니다.

대안을 사용하십시오. 가는 길입니다.

저는 Java 프로그래머이지만 이와 같은 것이 작동합니다.

List<Type> Os;
List<Type> Temp;
...
foreach (Type o in Os)
    if (o.cond)
        Temp.add(o);
Os.removeAll(Temp);  

방금 분석 라이브러리에 그 문제가있었습니다. 나는 이것을 시도했다 :

for (int i = 0; i < list.Count; i++)
{                
   if (/*condition*/)
   {
       list.RemoveAt(i);
       i--;
   }
}

그것은 매우 간단하지만 나는 어떤 깨지는 지점을 생각하지 않았습니다.

여기에 있습니다 가장 쉬운 솔루션 가장 단순한

문제:

일반적으로 원래 목록에서 제거하고 있으며, 이는 목록 수 및 반복자 위치를 유지하는 문제가 발생합니다.

List<Type> Os = ....;
Os.ForEach(
    delegate(Type o) {
        if(!o.cond) Os.Remove(o);
    }
);

해결책 - LINQ.ForEach:

내가 추가 한 모든 것이 참고 ToList(). 이로 인해 Foreach On을 수행하는 새 목록이 생겨서 원래 목록을 제거하지만 전체 목록을 계속 반복 할 수 있습니다.

List<Type> Os = ....;
Os.Tolist ().ForEach(
    delegate(Type o) {
        if(!o.cond) Os.Remove(o);
    }
);

솔루션 - 규칙적 foreach:

이 기술은 정기적으로 작동합니다 foreach 진술.

List<Type> Os = ....;
foreach(Type o in Os.Tolist ()) {
  if(!o.cond) Os.Remove(o);
}

원래 목록에 원래 목록에 포함되지 않으면이 솔루션에 작동하지 않습니다. struct 요소.

나는 당신이 다른 것을 요구했지만, 당신이 조건부로 많은 요소를 제거하고 싶다면 Lambda 표현을 사용할 수 있습니다.

Os.RemoveAll(o => !o.cond);
 Os.RemoveAll(delegate(int x) { return /// });

술어를 만족시키지 못하고 리버징 (0, index)을 수행하는 첫 번째 항목의 색인을 찾으려고 노력합니다. 다른 것이 없다면 전화를 제거해야합니다.

업데이트 : 완전성을 위해 추가되었습니다

몇몇은 대답했듯이 getEnumerator ()와 반복하는 동안 컬렉션을 수정해서는 안됩니다 (예제 foreach). 프레임 워크는 예외를 던지면이 작업을 수행하지 못하게합니다. 이것에 대한 일반적인 colution은 "수동으로"반복하는 것입니다. for (다른 답변 참조). 아이템을 건너 뛰지 않거나 동일한 항목을 두 번 다시 평가하지 않도록 색인에주의하십시오 ( i-- 또는 뒤로 반복).

그러나 특정 사례의 경우 아래의 제거 작업 ... 아래의 원본 답변을 최적화 할 수 있습니다.


주어진 조건을 충족 할 때까지 모든 항목을 제거하는 것이라면 (코드가하는 일)이 작업을 수행 할 수 있습니다.

bool exitCondition;

while(list.Count > 0 && !(exitCondition = list[0].Condition))
   list.RemoveAt(0);

또는 단일 제거 작업을 사용하려면 :

SomeType exitCondition;
int index = list.FindIndex(i => i.Condition);

if(index < 0)
    list.Clear();
else
{
    exitCondition = list[0].State;
    list.RemoveRange(0, count);
}

참고 : 나는 그것을 가정하기 때문에 item.Condition ~이다 bool, 나는 사용하고있다 item.State 출구 조건을 저장합니다.

업데이트 : 두 예제에 종료 조건을 확인하고 저장

LINQ로 할 수 있습니다

MyList = MyList.Where(x=>(someCondition(x)==true)).ToList()

목록이 크지 않다는 것을 알고 있다면 사용할 수 있습니다.

foreach (Type o in new List<Type>(Os))
    ....

목록의 임시 복제본이 생성됩니다. remove () 호출은 반복자를 방해하지 않습니다.

보다 Enumerable.SkipWhile()

Enumerable.SkipWhile( x => condition).ToList()

일반적으로 목록을 돌연변이하지 않으면 라이브가 훨씬 쉬워집니다. :)

이것에 대한 좋은 토론이 있습니다 목록을 반복하면서 목록에서 항목을 제거합니다 .

그들은 제안합니다 :

for(int i = 0; i < count; i++)
{
    int elementToRemove = list.Find(<Predicate to find the element>);

    list.Remove(elementToRemove);
}

Anzurio의 솔루션은 아마도 가장 간단한 솔루션이지만 유틸리티 라이브러리에 인터페이스/클래스를 추가하는 것이 마음에 들지 않는다면 또 다른 깨끗한 솔루션이 있습니다.

이렇게 쓸 수 있습니다

List<Type> Os;
...
var en = Os.GetRemovableEnumerator();
while (en.MoveNext())
{
    if (en.Current.Cond)
        en.Remove();
}

영감을 얻은 다음 인프라를 넣으십시오 Java 's Iterator<T>.remove, 유틸리티 라이브러리로 :

static class Extensions
{
    public static IRemovableEnumerator<T> GetRemovableEnumerator<T>(this IList<T> l)
    {
        return new ListRemovableEnumerator<T>(l);
    }
}

interface IRemovableEnumerator<T> : IEnumerator<T>
{
    void Remove();
}

class ListRemovableEnumerator<T> : IRemovableEnumerator<T>
{
    private readonly IList<T> _list;
    private int _count;
    private int _index;
    public ListRemovableEnumerator(IList<T> list)
    {
        _list = list;
        _count = list.Count;
        _index = -1;
    }

    private void ThrowOnModification()
    {
        if (_list.Count != _count)
            throw new InvalidOperationException("List was modified after creation of enumerator");
    }
    public void Dispose()
    {
    }

    public bool MoveNext()
    {
        ThrowOnModification();
        if (_index + 1 == _count)
            return false;
        _index++;
        return true;
    }

    public void Reset()
    {
        ThrowOnModification();
        _index = -1;
    }

    object IEnumerator.Current
    {
        get { return Current; }
    }

    public T Current
    {
        get { return _list[_index]; }
    }

    public void Remove()
    {
        ThrowOnModification();
        _list.RemoveAt(_index);
        _index--;
        _count--;
    }
}

방금 같은 문제가 있었고 다음을 사용하여 해결했습니다.

foreach (Type o in (new List(Os))) { if (something) Os.Remove(o); }

목록의 사본을 통해 반복되고 원본 목록에서 제거됩니다.

목록에서 제거 할 항목을 추가 한 다음 사용하여 이러한 항목을 제거하십시오. RemoveAll:

List<Type> Os;
List<Type> OsToRemove=new List<Type>();
...
foreach (Type o in Os){
    if (o.cond)
        return;
    else
        OsToRemove.Add(o);
}
Os.RemoveAll(o => OsToRemove.Contains(o));
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top