2009-06-30 4 views
2

좋아요. Dictionary 객체에 무작위로 저장된 기본 클래스를 기반으로하는 일련의 객체가 있습니다. 예 :Dictionary에서 특정 객체 유형을 선택하고 삭제하는 가장 효율적인 방법입니다.

class TypeA 
{ 
    public int SomeNumber {get; set;} 
    public void SomeFunction() 
} 

class TypeB : TypeA 
{ 
    public string SomeString {get; set;} 
} 

class TypeC : TypeA 
{ 
    public bool StuffReady() 
} 


Dictionary listOfClasses <long, TypeA>; 

키 값은 사전에 배치 된 개체 수의 실행 횟수입니다. 현재 사전 수와 일치하지 않습니다.

TypeB의 개체를 찾고 SomeString == "123"이라고 말하고 제거하고 싶습니다. 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

답변

5

다음 (또는 당신이 첫 번째 발생을 제거 할 경우) :

var found = listOfClasses.FirstOrDefault 
    (
     x => (x.Value is TypeB) && (((TypeB)x.Value).SomeString == "123") 
    ); 

if (found.Value != null) 
{ 
    listOfClasses.Remove(found.Key); 
} 

하는 경우가 여러 개의 일치하는 개체가있을 수 있으며 모두 제거하려고합니다.

var query = listOfClasses.Where 
    (
     x => (x.Value is TypeB) && (((TypeB)x.Value).SomeString == "123") 
    ); 

// the ToArray() call is required to force eager evaluation of the query 
// otherwise the runtime will throw an InvalidOperationException and 
// complain that we're trying to modify the collection in mid-enumeration 
foreach (var found in query.ToArray()) 
{ 
    listOfClasses.Remove(found.Key); 
} 
+0

SomeString 값이 "123"인 개체가 하나만 있어야합니다. 이를 보장하기 위해 동일하거나 유사한 코드를 사용하겠습니다. 컴파일러에서 'found'에 대해 null 체크를 허용하지 않지만 'found'에 값이없는 경우 Remove 문에서 예외가 발생하지 않습니다. – ChrisBD

+0

@ChrisBD : 잘 잡으세요. 발견 된 항목이 없을 때 Remove를 호출하면 Key = 0 인 합법적 인 사전 항목이있는 경우 문제가 발생할 수 있습니다 (항목을 찾을 수없는 경우 found.Key의 값은 기본적으로 0이되므로). found.Value에 대해 null 체크를 수행하도록 코드를 업데이트했습니다. – LukeH

+0

@ 루크. 좋은 점은 검사가 있는지 여부를 확신 할 수 없었습니다. 값이 필요할 것입니다. 그러나 키 값이 0 일 가능성이 있다는 관찰에 동의합니다. – ChrisBD

3

TypeA 클래스와 사전 키 간의 매핑이없는 것으로 나타납니다. 키는 long 유형이며 클래스에 해당 유형의 특성이 없습니다. 따라서 키에 직접 액세스 할 수있는 KeyValuePair 인스턴스 컬렉션을 검색해야합니다.

보십시오 당신은 단지 하나의 일치 객체가 될 것이라고 확신하는 경우

var found = listOfClasses 
    .Where(p => p.Value.SomeString == "123"). 
    .Where(p => p.Value.GetType() == typeof(TypeB)) 
    .Single(); 
listOfClasses.Remove(found.Key); 
+0

Thios는 컴파일하기 전에 SomeString 속성에 액세스하려면 캐스트가 필요하지만 런타임시 예외가 throw됩니다. 이는 IEnumerable 및 KeyValue 쌍과 관련이 있습니다. 아직도 +1로 생각 하더군요. – ChrisBD

0

실행중인 파일을 저장해야합니다 각 개체에 ngth. 속성을 RunningLengthTypeA에 추가하십시오. 그런 다음 두 사전을 사용하여 TypeA 개체를 저장하고 TypeB 개체를 저장합니다.

개체를 만들 때 (TypeA에서 내림차순 유형) ​​항상 첫 번째 사전에 추가하십시오. 생성 된 객체가 TypeB의 경우 두 번째 사전에 추가 :

Dictionary listOfClasses <long, TypeA>; 
Dictionary listOfTypeBClasses <string, TypeB>; 

TypeA newOject = TypeAFactory.Create(); 

if(newObject is TypeB) 
{ 
    TypeB objB = newObj as TypeB; 
    listOfTypeBClasses[objB.SomeString] = objB; 
} 

가 SomeString와 b를 입력의 객체를 제거하려면 = 당신이 다음 성능면에서 찾는 경우 "123"

if(listOfTypeBClasses.ContainsKey("123")) 
{ 
    long keyA = listOfTypeBClasses["123"].RunningLength; 
    listOfClasses.Remove(keyA); 
    // if required remove the item from listOfTypeBClasses as well 
    listOfTypeBClasses.Remove("123"); 
} 
0

루프가 더 좋은 방법이지만, 코드의 압축성 또는 코드 관리 관점에서 보면 LINQ가 그 길입니다.

+0

성능 차이는 매우 작고 매우 작을 것입니다. –

+0

이 경우에는 LINQ 쿼리와 "foreach"루프 사이에 성능상의 차이가 거의 없을 것으로 생각됩니다. (항상 그렇듯이, 퍼포먼스가 그렇게 중요하다면 프로파일 링/벤치 마크를해야합니다.) – LukeH

관련 문제