2013-12-11 62 views
0

有什麼辦法來不是每次檢查鍵是否已經存在?字典/ Hashset構建優化

假設

  • 我們不知道所有可能的密鑰之前,我們通過列表
  • 迭代的新途徑應該提高工作效率

    var list = new List<Person>(); // { int Id; int DepartmentId; string Name; } 
    ... // let's imagine that list is getting filled 
    
    var dict = new Dictionary<int, List<Person>>(); 
    
    foreach (var p in list) 
    { 
        if(!dict.ContainsKey(p.DepartmentId)) 
         dict.Add(p.DepartmentId, new List<int>()); 
    
        dict[p.DepartmentId].Add(p); 
    } 
    

回答

2

我可以看到兩個改進,然而他們每個人固有地仍然檢查關鍵存在。

第一個減少了訪問字典的次數。這在理論上是可能的,這會更快,但計算複雜度保持不變,並在實踐中的差異可能是微不足道的:

1)

var dict = new Dictionary<int, List<Person>>(); 

foreach (var p in list) 
{ 
    List<Person> value = null; 

    if(!dict.TryGetValue(p.DepartmentId, out value)) 
    { 
     value = new List<int>(); 
     dict.Add(p.DepartmentId, value); 
    } 

    value.Add(p); 
} 

第二個改進增加了一些語法糖:

2)

public static class DictionaryExtensions 
{ 
    public static TValue GetOrAdd<TKey, TValue>(
     this IDictionary<TKey, TValue> dictionary, 
     TKey key) where TValue : new() 
    { 
     TValue value; 
     if (!dictionary.TryGetValue(key, out value)) 
     { 
      value = new TValue(); 
      dictionary.Add(key, value); 
     } 

     return value; 
    } 
} 

然後:

foreach (var p in list) 
{ 
    dict 
     .GetOrAdd(p.DepartmentId) 
     .Add(p.DepartmentId); 
} 

由於Servy指出的那樣,你可能要添加一個參數GetOrAdd擴展到有超過創造的默認值進行更多的控制。

+0

我會調用擴展'GetOrAdd',以符合'ConcurrentDictionary'的版本。您也可以考慮遵循其示例,並讓它接受創建該值的委託,但不存在的情況。 – Servy

+0

@Servy很好的建議。在我的代碼中,我有一個默認值的第三個參數。然而,我決定放棄這個答案,以使結果代碼更加簡潔。 – BartoszKP