2011-09-01 2 views
1

사전에 문제가 있습니다. 도와 주시면 감사하겠습니다.사전 및 KeyValue 쌍

class MainCollection<TKey1, TKey2, TValue> : Dictionary<KeyValuePair<TKey1, TKey2>, TValue> 

문제는 내가 TKey1 또는 TKey2하여 사전에서 요소를 얻을 질수 있다는 것입니다 :

나는 다음과 같은 선언을합니다. TKey1 및 TKey2가 아닌 TKey1 또는 TKey2로만 요소를 가져 오는 방법이 있습니까?

는 다음 코드 작성 :

public TValue GetItemByKey1(TKey1 key) 
{ 
    MainCollection<int, int, string> Coll = new MainCollection<int, int, string>(); 
    var value = from s in Coll where s.Key.Key == key select s.Value; 
} 

을하지만 이미 두 가지 문제가 있습니다

  1. 컴파일 오류 : s.Key.Key는 == 키는 => 연산자 == 적용 할 수 없습니다 int와 TKey1 타입에
  2. 보기 흉하게 보입니다. 편집이 성공하더라도이 항목을 가져 오는 가장 빠른 방법이라고 확신하지 못합니다. 나는 그 사전이 더 나은 것이되어야한다고 생각한다.

어떻게 이러한 오류를 해결할 수 있습니까? 나는 여기에 관련된 질문을 찾지 못했습니다. 미리 감사드립니다.

public TValue GetItemByKey1(TKey1 key) 
{   
    var value = from s in this.Keys where s.Key.Key == key select this[s]; 
    return value.SingleOrDefault(); 
} 

당신은 TKey2 위해 유사한 방법이있을 수 있습니다

+0

왜'TKey1'가'int'이라고 생각합니까? 코드가 의미가 없습니다. – SLaks

+0

KeyValuePair를 사용하는 특별한 이유가 있습니까? 두 개의 키를 저장하기 위해 공용 구조체를 사용하여 간단한 구조체 (Equals 및 GetHashCode 구현)를 사용할 수 있습니다. 위 코드에서 == 연산자는 정적으로 입력되었으므로 Equals 메서드를 사용하여 등호 테스트를 수행해야합니다. – Hasanain

+0

사용중인 .Net 버전은 무엇입니까? .Net 4 인 경우, 키에'Tuple '을 사용하십시오. – IAbstract

답변

5

그래, TKey1 또는 TKey2으로 조회 할 수 있기를 원합니다. 그러면 원하는 것은 3 개의 사전입니다. 하나는 각 키에 대한 것이고, 다른 하나는 키 쌍에 대한 것입니다. 단지 (TFirstKey, TSecondKey)에 의해 조회

class Foo<TFirstKey, TSecondKey, TValue> { 
    private readonly Dictionary<TFirstKey, List<TValue>> firstDictionary 
     = new Dictionary<TFirstKey, List<TValue>>(); 
    private readonly Dictionary<TSecondKey, List<TValue>> secondDictionary 
     = new Dictionary<TSecondKey, List<TValue>>(); 
    private Dictionary<Tuple<TFirstKey, TSecondKey>, TValue> dictionary 
     = new Dictionary<Tuple<TFirstKey, TSecondKey>, TValue>(); 

    public IEnumerable<TValue> GetByFirstKey(TFirstKey firstKey) { 
     return this.firstDictionary[firstKey]; 
    } 

    public IEnumerable<TValue> GetBySecondKey(TSecondKey secondKey) { 
     return this.secondDictionary[secondKey]; 
    } 

    public TValue GetByKey(TFirstKey firstKey, TSecondKey secondKey) { 
     return this.dictionary[Tuple.Create(firstKey, secondKey)]; 
    } 

    public void Add(TFirstKey firstKey, TSecondKey secondKey, TValue value) { 
     this.dictionary.Add(Tuple.Create(firstKey, secondKey), value); 
     if(this.firstDictionary.Keys.Contains(firstKey)) { 
      this.firstDictionary[firstKey].Add(value); 
     } 
     else { 
      this.firstDictionary.Add(firstKey, new List<TValue> { value }); 
     } 
     if(this.secondDictionary.Keys.Contains(secondKey)) { 
      this.secondDictionary[secondKey].Add(value); 
     } 
     else { 
      this.secondDictionary.Add(secondKey, new List<TValue> { value }); 
     } 
    } 
} 

참고 고유, 그래서 당신은 컬렉션을 반환 GetByFirstKeyGetBySecondKey이 필요합니다.

나머지 세부 정보는 제공해 드리겠습니다.

요점은 두 키 중 빠른 검색을 원할 경우 두 개의 사전 (키 쌍의 각 좌표에 하나씩)이 필요하다는 것입니다. 하나를 사용하면 키 집합을 쿼리하여 작업 할 수 있지만 속도가 느립니다 (키를 검색 할 때 선형 임).

+0

두 개의 사전이 필요하지 않습니다. – IAbstract

+1

@IAbstract : 마지막 단락을 읽으십시오. – jason

+0

와우! 감사! 감사! 너 정말로 나를 구했어! – Laserson

1

그냥 콜렉션 자체에 메서드를 추가합니다.

다른 방법으로는 사전이 사용하는 해시 테이블을 활용하는 대신 키 컬렉션을 반복하므로이 조회는 표준 사전 검색보다 느리게 이 될 것입니다.

+0

감사합니다. 당신이 정말로 나를 도왔습니다! – Laserson

1

KeyValuePair<TKey, TValue>을 사용하는 것이 좋습니다. 왜냐하면 KVP가 구조체이고 사전의 키가되는 것이 개체가 잠시 동안있을 것임을 나타 내기 때문입니다. 대신 Tuple<T1, T2>을 권하고 싶습니다. 이점은 Tuple이 참조 유형이므로 복사하지 않고 자유롭게 전달할 수 있다는 것입니다. 또한 Tuple은 KVPair와 마찬가지로 읽기 전용 객체입니다. 여기에 쓸 방법은 다음과 같습니다.

class Program 
    { 
     static void Main(string[] args) 
     { 
      MainCollection<int, string, DateTime> collection = new MainCollection<int, string, DateTime>(); 

      collection.Add(Tuple<int, string>.Create(1, "Bob"), new DateTime(1992, 12, 1)); 
      collection.Add(Tuple<int, string>.Create(2, "James"), new DateTime(1945, 9, 1)); 
      collection.Add(Tuple<int, string>.Create(3, "Julie"), new DateTime(1976, 7, 15)); 

      DateTime date; 

      date = collection.GetValue(1); 
      Console.WriteLine("Bob birthdate: {0}", date); 

      date = collection.GetValue("Julie"); 
      Console.WriteLine("#3 birthdate: {0}", date); 

      Console.ReadLine(); 
     } 
    } 

    public class MainCollection<TKey1, TKey2, TValue> 
    { 
     Tuple<TKey1, TKey2> key; 
     Dictionary<Tuple<TKey1, TKey2>, TValue> mainCollection = new Dictionary<Tuple<TKey1, TKey2>, TValue>(); 

     public void Add(Tuple<TKey1, TKey2> Key, TValue Value) 
     { 
      mainCollection.Add(Key, Value); 
     } 

     public TValue GetValue(TKey1 Key) 
     { 
      return mainCollection.Where(k => k.Key.Item1.Equals(Key)) 
           .Select(v => v.Value) 
           .FirstOrDefault(); 
     } 

     public TValue GetValue(TKey2 Key) 
     { 
      return mainCollection.Where(k => k.Key.Item2.Equals(Key)) 
           .Select(v => v.Value) 
           .FirstOrDefault(); 
     } 

    } 

    public class Tuple<T1, T2> 
    { 
     readonly T1 item1; 
     readonly T2 item2; 

     Tuple(T1 item1, T2 item2) 
     { 
      this.item1 = item1; 
      this.item2 = item2; 
     } 

     public static Tuple<T1, T2> Create(T1 Item1, T2 Item2) 
     { 
      return new Tuple<T1, T2>(Item1, Item2); 
     } 

     public T1 Item1 
     { get { return item1; } } 

     public T2 Item2 
     { get { return item2; } } 
    } 
} 

참고 : .Net 4를 사용하지 않는 경우를 대비하여 튜플 구현을 포함 시켰습니다.0

업데이트 :
이 같을 것이다 여러 사전을 사용하는 MainCollection 개체를 변환 :

public class MainCollection<TKey1, TKey2, TValue> 
{ 
    Tuple<TKey1, TKey2> key; 
    Dictionary<TKey1, Tuple<TKey1, TKey2>> k1Dictionary = new Dictionary<TKey1, Tuple<TKey1, TKey2>>(); 
    Dictionary<TKey2, Tuple<TKey1, TKey2>> k2Dictionary = new Dictionary<TKey2, Tuple<TKey1, TKey2>>(); 
    Dictionary<Tuple<TKey1, TKey2>, TValue> mainCollection = new Dictionary<Tuple<TKey1, TKey2>, TValue>(); 

    public void Add(Tuple<TKey1, TKey2> Key, TValue Value) 
    { 
     mainCollection.Add(Key, Value); 

     k1Dictionary.Add(Key.Item1, Key); 
     k2Dictionary.Add(Key.Item2, Key); 
    } 

    public TValue GetValue(TKey1 Key) 
    { 
     return mainCollection[k1Dictionary[Key]]; 
    } 

    public TValue GetValue(TKey2 Key) 
    { 
     return mainCollection[k2Dictionary[Key]]; 
    } 
} 
+0

놀라운! 그것은 내가 당신의 대답에 대해 10 개의 상향 회선을 만들지 못하는 것이 너무 아쉽습니다! – Laserson

+0

나는 두 개의 사전의 이점을 깨달았습니다. 두 개의 사전으로 사용하기 위해 샘플을 다시 작성할 수 있습니까? – Laserson

+0

@Laserson : 업데이트 참조 – IAbstract