2009-04-24 14 views
5

私は次のようなコードを持っています:私はC#で2回ハッシュする必要がありますか?

class MyClass 
{ 
    string Name; 
    int NewInfo; 
} 

List<MyClass> newInfo = .... // initialize list with some values 
Dictionary<string, int> myDict = .... // initialize dictionary with some values 

foreach(var item in newInfo) 
{ 
    if(myDict.ContainsKey(item.Name)) // 'A' I hash the first time here 
     myDict[item.Name] += item.NewInfo // 'B' I hash the second (and third?) time here 
    else 
     myDict.Add(item.Name, item.NewInfo); 
} 

ディクショナリで2回の参照を避ける方法はありますか?最初にエントリが含まれているかどうかを確認し、 'B'行には2つのハッシュ・ルックアップがあります.1つはint値を取得し、もう1つはそれを更新します。

答えて

14

はい - Dictionary.TryGetValueを使用してください。値を受け取るにはoutパラメータが必要で、値が見つかったかどうかが返されます。

​​

しかし、我々は、この特定のケースにそのよりも良い行うことができます。ここでは、あなたの調整のコードです。 のキーがではない場合、outのパラメータは0に設定されます。新しい値をitem.NewInfoまたはitem.NewInfo + valueに設定するため、どちらの場合も同じことをしています。私たちは、メソッドの戻り値を無視し、単に使用することができます。しかし、非常に珍しい

foreach(var item in newInfo) 
{ 
    int value; 
    myDict.TryGetValue(item.Name, out value); 
    myDict[item.Name] = value + item.NewInfo; 
} 

- 通常あなたが戻り値を使用しますが、明らかに。

余談

それはあなたが本当にそれが動作GetValueOrDefault操作をやっているだけであるためです。

foreach(var item in newInfo) 
{ 
    myDict[item.Name] = myDict.GetValueOrDefault(item.Name) + item.NewInfo; 
} 

(あなたが潜在的に、より明確にするためGetValueOrDefault(item.Name, 0)を呼び出すことができます。は簡潔なあなたのコードを明確にすることができ、その時点で

public static TValue GetValueOrDefault<TKey, TValue> 
    (this IDictionary<TKey, TValue> dictionary, TKey key) 
{ 
    TValue value; 
    dictionary.TryGetValue(key, out value); 
    return value; 
} 

public static TValue GetValueOrDefault<TKey, TValue> 
    (this IDictionary<TKey, TValue> dictionary, TKey key, 
    TValue customDefault) 
{ 
    TValue value; 
    if (dictionary.TryGetValue(key, out value)) 
    { 
     return value; 
    } 
    else 
    { 
     return customDefault; 
    } 
} 

:実際には、それが有効な拡張メソッドのペアになります。)戻るポイントへ

...

あなたはまだ2つの検索をしていることに注意してください - 一つは値を取得するためのもので、もう一つは追加/置換するものです。 TValue型の引数を何か変更可能にすることなく、それを避けることはできません。それは可能ですが、ひどくいいことではありません。

の3つの検索 - ContainsKeyの場合は1つ、値が置き換えられる場合は2つ(キーが見つかった場合)です。 (。item.Nameは一度だけ評価が、それは同じだそれ以外のことでしょう):それは私たちが+=を展開することを確認する方が簡単です

myDict[item.Name] = myDict[item.Name] + item.NewInfo; 

別余談

それは次のようになりますDictionaryの操作をして、古い値に基づいて新しい値を得るための関数に基づいて "検索と置き換え"を実行しました。(キーが見つからなかった場合やTValueのデフォルト値)replacementFunctionは、現在の値を取る関数であるだろうとブールキー実際に見つかったかどうかと言って、そして戻っ

bool Update(TKey key, Func<TValue, bool, TValue> replacementFunction) 

新しい値次に、辞書はキーをルックアップし、置換関数を呼び出してその場で値を更新することができる。 (これは拡張メソッドとして実装できません)

+1

これは機能的であるが、単にint型のデフォルト値は防御コーディング観点から0であるので、値が0のみであることに注意してください、これは簡潔さのために、読みやすさ(及び潜在的に保守性)を犠牲にします。私はあなたが持っているものに固執します。正直です。 –

+0

私はもっと大きな警告を出します - それは確かに特別なケースです。 –

+0

まだ各項目を2回ハッシュしていませんか?一旦TryGetValueに入ったら、もう一度 'myDict [item.Name]'と答えてください。 –

1

いいえ、ほとんどの場合、2回ハッシュする必要はありません。その秘密は、intの代わりにオブジェクトを辞書に格納することです。

class Program 
{ 
    static void Main(string[] args) 
    { 
     var newInfo = new List<MyClass>(); 
     var myDict = new Dictionary<string, MyClass>(); 

     foreach (var item in newInfo) 
     { 
      MyClass temp; 
      if (!myDict.TryGetValue(item.Name, out temp)) 
      { 
       temp = new MyClass() { Name = item.Name }; 
       myDict.Add(temp.Name,temp); 
      } 

      temp.NewInfo += 1; 

     } 

    } 
} 


class MyClass 
{ 
    public string Name; 
    public int NewInfo; 
} 
+0

少なくともパブリックフィールドの代わりにそれらのプロパティを作る... ick! :) –

関連する問題