[C#] 반복하는 동안 일반 목록에서 요소를 제거하는 방법은 무엇입니까?

나는 더 나은 것을 찾고 있습니다 각각 처리 해야하는 요소 목록으로 작업하고 결과에 따라 목록에서 제거되는 패턴 을있습니다.

당신은 사용할 수 없습니다 .Remove(element)돌며 foreach (var element in X)(이 결과 때문에 Collection was modified; enumeration operation may not execute.예외) … 당신은 또한 사용할 수 없습니다 for (int i = 0; i < elements.Count(); i++).RemoveAt(i) 이에 수집 상대적으로 사용자의 현재 위치를 방해하기 때문 i.

이것을 할 수있는 우아한 방법이 있습니까?



답변

for 루프와 반대로 목록을 반복하십시오.

for (int i = safePendingList.Count - 1; i >= 0; i--)
{
    // some code
    // safePendingList.RemoveAt(i);
}

예:

var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
    if (list[i] > 5)
        list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));

또는 술어와 함께 RemoveAll 메소드 를 사용하여 다음 을 테스트 할 수 있습니다 .

safePendingList.RemoveAll(item => item.Value == someValue);

다음은 간단한 예입니다.

var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));


답변

간단하고 간단한 솔루션 :

컬렉션 에서 뒤로 실행되는 표준 for-loop RemoveAt(i)를 사용하고 요소를 제거하십시오.


답변

컬렉션을 반복하면서 컬렉션에서 요소를 제거하려면 역 반복이 가장 먼저 떠 오릅니다.

운 좋게도, 불필요한 입력을 필요로하고 오류가 발생하기 쉬운 for 루프를 작성하는 것보다 더 우아한 솔루션이 있습니다.

ICollection<int> test = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});

foreach (int myInt in test.Reverse<int>())
{
    if (myInt % 2 == 0)
    {
        test.Remove(myInt);
    }
}


답변

 foreach (var item in list.ToList()) {
     list.Remove(item);
 }

이 경우 “.ToList ()”를 추가 지칠대로 지친를 빼고 목록 (또는 LINQ 쿼리의 결과), 직접 “목록”에서 “항목”을 제거 할 수 있습니다에 ” 컬렉션 수정; 열거 작업이 실행되지 않을 수 있습니다 .” 오류. 컴파일러는 “목록”의 복사본을 만들어서 어레이에서 안전하게 제거를 수행 할 수 있습니다.

하지만 이 패턴은 매우 효율적이지 않습니다, 그것은 자연적인 느낌을 가지고 있습니다 거의 모든 상황에 유연 . 예를 들어 각 “항목”을 DB에 저장하고 DB 저장에 성공한 경우에만 목록에서 제거하십시오.


답변

당신이 요소 선택 않습니다 오히려 당신이 요소를 제거하는 것보다 원하는을 하지 않습니다 싶어합니다. 이것은 요소를 제거하는 것보다 훨씬 쉽습니다 (일반적으로 더 효율적입니다).

var newSequence = (from el in list
                   where el.Something || el.AnotherThing < 0
                   select el);

아래에 Michael Dillon이 남긴 의견에 대한 답변으로 이것을 의견으로 게시하고 싶지만 어쨌든 내 대답에 너무 길어서 아마도 유용합니다.

개인적으로 한 번에 하나씩 항목을 제거하지는 않습니다. 제거가 필요한 경우 호출 RemoveAll하면 술어를 취하고 내부 배열을 한 번만 재정렬하는 반면 제거하는 모든 요소에 Remove대해 Array.Copy작업을 수행합니다. RemoveAll훨씬 더 효율적입니다.

그리고 목록 반복 당신이있는 거 뒤로, 당신은 이미 당신이 전화에 훨씬 더 효율적으로 될 수 있도록, 제거 할 요소의 인덱스가있을 때 RemoveAt, 때문에Remove 첫 번째 요소의 인덱스를 찾기 위해리스트의 탐색을 수행하면 ‘제거하려고하지만 이미 해당 색인을 알고 있습니다.

결국, 나는 Removefor-loop를 호출 할 이유가 없습니다 . 이상적으로는 가능하다면 위의 코드를 사용하여 필요에 따라 목록에서 요소를 스트리밍하므로 두 번째 데이터 구조를 전혀 만들지 않아도됩니다.


답변

일반 목록에서 ToArray ()를 사용하면 일반 목록에서 Remove (item)를 수행 할 수 있습니다.

        List<String> strings = new List<string>() { "a", "b", "c", "d" };
        foreach (string s in strings.ToArray())
        {
            if (s == "b")
                strings.Remove(s);
        }


답변

.ToList ()를 사용하면이 질문에 설명 된대로 목록을 복사합니다.
ToList ()-새 목록을 작성합니까?

ToList ()를 사용하면 실제로 사본을 반복하므로 원래 목록에서 제거 할 수 있습니다.

foreach (var item in listTracked.ToList()) {

        if (DetermineIfRequiresRemoval(item)) {
            listTracked.Remove(item)
        }

     }