2009-10-09 11 views
4

목록에서 항목을 제거 할 수 있습니까? <> 반복하면서 항목을 제거 할 수 있습니까? 이 방법이 효과가 있습니까, 아니면 더 좋은 방법이 있을까요?List <>에서 항목을 제거 할 수 있습니까? C#

내 코드 :

foreach (var bullet in bullets) 
    { 
    if (bullet.Offscreen()) 
    { 
     bullets.Remove(bullet); 
    } 
    } 

-edit- 죄송합니다 사람, 이것은 실버 게임입니다. 저는 Silverlight가 Compact Framework와 다른 것을 알지 못했습니다.

+0

이 질문을 참조하십시오.com/questions/308466/enumerable-collection-while-iterating-throu에서 아이템을 수정하거나 삭제하는 방법 –

답변

10

편집는 : 문제는 분명히 RemoveAll on List`T를 지원하지 않습니다 실버에 관한되고, 명확히한다. 당신이 당신의 제거 기준을 표현하는 람다를 쓸 수 full framework, CF, XNA versions 2.0+

에서 사용할 수 있습니다 :

bullets.RemoveAll(bullet => bullet.Offscreen()); 

또는 대신 사람을 제거하는, 당신이 원하는 않는 사람을 선택할 수 있습니다 당신은하지 않습니다

bullets = bullets.Where(b => !b.OffScreen()).ToList(); 

또는 순서를 뒤로 이동 인덱서를 사용

for(int i=bullets.Count-1;i>=0;i--) 
{ 
    if(bullets[i].OffScreen()) 
    { 
     bullets.RemoveAt(i); 
    } 
} 
+0

'List .RemoveAll'과 비교하면 매우 비효율적입니다 (내 답변 참조). –

+0

@ 280z28 예, RemoveAll을 잊어 버렸습니다. –

+0

두 번째 버전이 가장 적합합니다 (역 반복). RemoveAll이 더 이상 작동하지 않는 것 같습니다 (사용되지 않음?). – Chris

4

foreach 루프 내에서 제거하려고 시도하면 예외가 발생합니다. for 루프를 사용하여 역순으로 반복해야합니다.

for (int count = bullets.Count - 1; count >= 0; count--) 
{ 
    if (bullets[count].Offscreen()) 
    { 
     //bullets.Remove(bullets[count]); 
     bullets.RemoveAt(count); 
    } 
} 
+0

이것은 좋은 생각입니다. 감사합니다. 생각하는 목록을 거꾸로 반복 할 때 성능 저하가 없을 것입니다. 루프에 대한 – Chris

+0

은 일반적으로 빠른 것으로 간주됩니다. 반대 방향으로 횡단하는 것은 정상적으로 그렇게하는 것과 크게 다르지 않습니다. 또한 임시 목록 복사가 없으므로 원본 컬렉션에 영향을줍니다. –

+0

또한 'removeat'는 '제거'보다 빠르다고 생각합니다. – Chris

2

이 목록에서 항목을 한 후, 삭제하는 항목을 포함하는 목록을 만드는 하나 더 :

List<Bullet> removedBullets = new List<Bullet>(); 

foreach(var bullet in bullets) 
{ 
    if (bullet.OffScreen()) 
    { 
    removedBullets.Add(bullet); 
    } 
} 

foreach(var bullet in removedBullets) 
{ 
    bullets.Remove(bullet); 
} 
+0

이것은 원래의 생각 이었지만, 실시간 게임 이후 가능한 오버 헤드로 인해 새로운 목록을 작성하는 데별로 열의가 없습니다. – Chris

17
bullets.RemoveAll(bullet => bullet.Offscreen()); 

편집 :-그대로는이 작품을 만들려면 실버 라이트에서 프로젝트에 다음 확장 메소드를 추가하십시오.

List<T>.RemoveAll처럼이 알고리즘은 O (N)입니다. 여기서 N은 목록에서 제거 된 요소의 수인 M (O * N)과 대조되는 목록의 길이입니다. 비 Silverlight 프레임 워크에서 발견 된 RemoveAll 메서드와 동일한 프로토 타입을 사용하는 확장 메서드이기 때문에 사용할 수있는 경우 기본 제공 메서드가 사용되며이 메서드는 Silverlight 빌드에 완벽하게 사용됩니다.

public static class ListExtensions 
{ 
    public static int RemoveAll<T>(this List<T> list, Predicate<T> match) 
    { 
     if (list == null) 
      throw new NullReferenceException(); 

     if (match == null) 
      throw new ArgumentNullException("match"); 

     int i = 0; 
     int j = 0; 

     for (i = 0; i < list.Count; i++) 
     { 
      if (!match(list[i])) 
      { 
       if (i != j) 
        list[j] = list[i]; 

       j++; 
      } 
     } 

     int removed = i - j; 
     if (removed > 0) 
      list.RemoveRange(list.Count - removed, removed); 

     return removed; 
    } 
} 
+0

좋아해요! 그레이트 대답 :) – Russell

+0

+1 당신이 나를 이길! :) –

+0

이것은 대답입니다, 다른 사람들이 자신의 파일을 삭제할 수 있다면 좋을 것입니다 ... – Benjol

2

으로 반복 : 당신이 그것을 필요로 할 때마다

public void RemoveIf<T>(ICollection<T> collection, Predicate<T> match) 
{ 
    List<T> removed = new List<T>(); 
    foreach (T item in collection) 
    { 
     if (match(item)) 
     { 
      removed.Add(item); 
     } 
    } 

    foreach (T item in removed) 
    { 
     collection.Remove(item); 
    } 

    removed.Clear(); 
} 

그리고 당신의 대리인과 전화 :

짧은 버전은 RemoveIf라는 확장 메서드를 만들 수 있다는 것입니다 foreach를 반복하지 말고 반복하십시오. 이것은 효과가있다.

3

이 시도 : HTTP : // 유래

bullets.RemoveAll(bullet => bullet.Offscreen()); 
관련 문제