2010-04-23 2 views
3

제 질문은 열거자가 SortedList에서 항목을 제거하는 것이 안전합니까?반복 중에 SortedList에서 삭제하는 것이 안전합니까?

SortedList<decimal, string> myDictionary; 
// omitted code 

IEnumerator<decimal, string> enum = myDictionary.GetEnumerator(); 

while(enum.MoveNext) 
{ 
    // is it ok to remove here? 
    myDictionary.Remove(enum.Current.Key); 
} 
+3

번호 당신은 – bitbonk

+1

당신은 또한'enum'는 예약어로'@ enum'을 할 수 있도록 변수'enum' 이름을 변경해야 할 것 인 InvalidOperationExcpetion을 얻어야한다 . – James

+2

예, 작동하지 않으므로 안전합니다. 삭제해야 할 항목 (예 : LINQ) –

답변

8

이렇게하면 예외가 발생합니다. 반복되는 동안 컬렉션을 수정할 수 없습니다.

조금 생각하면 이유를 알 수 있습니다. 컬렉션에서 추가 또는 제거가 허용 된 경우 동일한 컬렉션에서 더 이상 반복하지 않습니다. 항목이 너무 많거나 (추가됨) 또는 부족한 경우 (제거 중)입니다.

+0

을 수령하기 위해 컬렉션을 쿼리 해보십시오. 허용되지 않는 이유를 설명 할 수 있다면 보너스 포인트를 제공해주세요. –

+0

여기 있습니다 : "인덱스 순서는 정렬 순서에 기반합니다.요소가 추가되면 올바른 정렬 순서로 SortedList에 삽입되고 그에 따라 색인이 조정됩니다. 요소가 제거되면 인덱싱도 그에 따라 조정됩니다. 따라서 특정 키/값 쌍의 인덱스는 요소가 SortedList 개체에 추가되거나 제거 될 때 변경 될 수 있습니다. "MSDN의 연결된 목록 설명서 –

+1

일부는 삭제해도 안전하고 일부는 그렇지 않은 STL 반복자에 대해 생각해 보았습니다. –

2

반복 중에 목록에 대한 작업은 일반적으로 지원되지 않습니다. 예상 된 동작은 예외를 throw하는 것이지만 컬렉션이 실패하더라도이를 제대로 작동해서는 안됩니다.

먼저 요소를 다른 목록에 복사 한 다음 수정할 새 항목 목록을 반복 할 수 있습니다.

2

아니요. InvalidOperationExcpetion이 발생합니다. 고정 인덱스가 있기 때문에 이미 열거 된 항목을 삭제할 수 있다는 것에 동의합니다. 그러나 문제는 다음과 같습니다.

SortedList의 구현은 제거가 열거 가능 항목의 추가 실행에 영향을 미치지 않는다는 것을 알기에 충분히 똑똑하지 않습니다. 그리고 그것을 간단하게 유지하고 잘 수행하기 위해서는 안됩니다.

4

이미 말씀 드렸듯이 당신이하려는 것은 불가능합니다. 그러나 대체 솔루션은 단순히 삭제 표시된 항목의 목록을 유지 한 다음이 후속 항목을 제거하는 것입니다. 또한 while 루프가 아닌 foreach을 선택합니다. 예를 들어 코드가 적습니다.

var removeList = new List<decimal>(); 
foreach (var item in myDictionary) 
{ 
    // have a condition which indicates which items are to be removed 
    if (item.Key > 1) 
    { 
     removeList.Add(item.Key); 
    } 
} 

아니면 단순히 삭제 항목을 검색하려는 경우, 그럼 그냥 목록에서 제거

var removeList = myDictionary.Where(pair => pair.Key > 1).Select(k => k.Key).ToList(); 

LINQ

를 사용합니다.

// remove from the main collection 
foreach (var key in removeList) 
{ 
    myDictionary.Remove(key); 
} 
+2

두 번째 예제가 효과가있을 것이라고 확신 하는가? 나는 그것을 시험하지 않았지만,'removeList'는 단지 질의를하고 또한 * 위에서 목록을 반복하여 이전과 같은 예외를 발생시킬 것이다. 나는 새로운 것을 얻기 위해'.ToList()'또는'.ToArray()'를 추가해야한다고 생각한다. – Oliver

+0

@Oliver : +1 좋은 점, 나 자신을 테스트 한 적이 없다. – James

2

다른 사람들이 이미 지적했듯이 효과가 없을 것입니다. 그러나 컬렉션이 SortedList이므로 RemoveAt 메서드를 사용할 수 있습니다.

이 방법은 제거 목록을 유지하기 위해 별도의 목록을 사용하는 O (n) 증가와 달리 오버 헤드가 필요 없으므로 메모리 프로파일이 약간 더 좋습니다. 또한 O (n^2 * log (n))와 반대되는 O (n^2) 성능 프로파일을 갖습니다. RemoveAt 메서드는 배열 복사를 수행해야하므로 O (n)입니다. Remove 메서드는 내부적으로 RemoveAt를 호출하기 전에 O (log (n)) 연산을 추가하여 인덱스를 찾습니다. 이 모든 것은 아마도 당신에게 문제가되지 않지만, 'n'이 많은 상황에 처했을 때 유용합니다.

var myDictionary = new SortedList<decimal, string>(); 

// omitted code 

int i = 0; 
while (myDictionary.Count > 0 && i < myDictionary.Count) 
{ 
    if (/* predicate to use for removal */) 
    { 
    myDictionary.RemoveAt(i); 
    } 
    else 
    { 
    i++; 
    } 
} 
+0

멋지다! if 요소에서'i' 요소를 검사하고 싶다면' myDictionary.Values ​​[i]', 밑받침 목록은 다음과 같습니다. 정렬. – v01pe

0

타 솔루션 :

  int counter= MyDictionary.Count; 
      if (counter == 0) 
       return; 

      for (int i = 0; i < counter;i++) 
      { 
       KeyValuePair<MyIdentifier, MyValue> key = (KeyValuePair<MyIdentifier, MyValue>)MyDictionary.ToArray()[i]; 
       MyIdentifier identifier = null; 

       if (key.Key != null) 
        identifier = key.Key as MyIdentifier; 

       if (identifier != null) 
        if (MyCondition) 
        { 
         MyDictionary.Remove(identifier); 
         counter--; 
        } 
      } 
관련 문제