2009-03-17 8 views
7

나는 List.RemoveAll (Predicate)을 모방하는 확장 메서드를 작성하려고 노력 해왔다.확장 메서드 사전 <TKey,TValue> .RemoveAll? 가능한가?

public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, 
            Predicate<KeyValuePair<TKey,TValue>> condition) 
{ 
    Dictionary<TKey,TValue> temp = new Dictionary<TKey,TValue>(); 

    foreach (var item in dict) 
    { 
     if (!condition.Invoke(item)) 
      temp.Add(item.Key, item.Value); 
    } 

    dict = temp; 
} 

모든 포인터 :

지금까지 나는이있어? 이것은 완전히 순진한 구현입니까?

+0

public static Dictionary<TKey, TValue> RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, Predicate<KeyValuePair<TKey,TValue>> condition) 

을 그리고 호출 코드는 말할 것이다 : 당신의 서명이 변경 것 KeyValuePair 대신 Key 만 일치하는 조건어를 사용하여 사전에서 쌍을 삭제 하시겠습니까? – base2

답변

16

사전 클래스를 값으로 전달하기 때문에 코드가 작동하지 않습니다. 즉, 최종 할당 (dict = temp)이 호출하는 함수에 표시되지 않습니다. C#에서는 확장 메서드 대상을 ref 또는 out으로 전달할 수 없습니다 (VB에서는 ByRef를 사용하는 것이 합법입니다).

대신 사전 인라인을 수정해야합니다. 목록의 할당 된 메모리의 크기를 줄이는 경우와 ToList의 순서를 스왑

public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, 
            Func<KeyValuePair<TKey,TValue>,bool> condition) 
{ 
    foreach (var cur in dict.Where(condition).ToList()) { 
     dict.Remove(cur.Key); 
    } 
} 

다음 편집

을보십시오. 이제는 제거 할 항목에 대한 목록 만 할당합니다. 제거 수가 0이 될 가능성이있는 경우 제거 할 수있는 키의 수는 사전의 크기가 작은 상대 인 경우

+0

매번 키 목록에 충분한 메모리를 할당하는 단점이 있습니다. 하지만 확실히 간단합니다 – ShuggyCoUk

+0

실제로 작동하지 않습니다 ... –

+0

@ 로브 어떻게 그렇게? 내가 사용했던 샘플 데이터에 대해 잘 작동합니다. – JaredPar

4
public static void RemoveAll<TKey,TValue>(
    this Dictionary<TKey,TValue> dict, 
    Predicate<KeyValuePair<TKey,TValue>> condition) 
{ 
    var toRemove = new List<TKey>(); 

    foreach (var item in dict) 
    { 
     if (!condition(item)) 
      toRemove.Add(item); 
    } 
    foreach (var key in toRemove) 
    { 
     dict.Remove(key); 
    } 
} 

이 빨라집니다 (당신은 더 빠르게 느리게뿐만 아니라 toRemove 목록을 작성하여이 작업을 할 수 있습니다.

이것은 Jared의 업데이트 된 답변과 동일하지만 원하는 경우 제거 목록 생성을 연기 할 수 있습니다. 문제가되지 않는 경우 (그리고 프로세스를 통해 부분적으로 중단 할 이유가없는 경우)) Jared 's는 더 깔끔하고 간단합니다.

+0

조건에 조건을 호출 할 필요가 없습니다. 왜냐하면 이미 조건이므로 대리자. 조건을 직접 호출 할 수 있습니다 (예 : 조건 (항목). – base2

+0

@ base2 원래 사용자 스타일을 복제하는 중이었습니다. Invoke 없이는 더 낫다는 것에 동의하지만, 나는 그것을 바꿀 것이다. – ShuggyCoUk

1

"dict"매개 변수가 refere에 의해 전달되지 않기 때문에이 방법이 작동하지 않습니다. nce이고 사실 ref는 확장 메서드의 첫 번째 매개 변수로 지원되지 않기 때문에 실제로는 사용할 수 없습니다.

public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, 
           Predicate<KeyValuePair<TKey,TValue>> condition) 
{ 
    var temp = new List<TKey>(); 

    foreach (var item in dict) 
    { 
     if (!condition(item)) 
      temp.Add(item.Key); 
    } 

    foreach (var itemKey in temp) 
     dict.Remove(itemKey) 
} 

RemoveAllByKey 및 RemoveAllByValue 구현도보고 싶습니다.

0

하지만 원하는 경우 새롭고 다른 사전을 반환 할 수 있습니다. 당신이 oldDict를 수정하기를 원한다면 당신이 이런 식으로 부를 것이다,

var newDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something")); 

을 그리고 :

oldDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something"));