2011-06-20 8 views
10

...私が探してる私は、C#/。NET技術を用いた高速マーチングアルゴリズムをコード化しようとしている旧C++/STLプログラマだ

C#の辞書に一つだけのルックアップを挿入して下さい - または - 存在しない場合は指定されたキーに値を挿入するSTLメソッド "map :: insert"に相当し、そうでない場合は既存のキーと値のペアにイテレータを返します。

私が見つけた唯一の方法は、二つのルックアップでこれを行います。TryGetValue内側1およびAddメソッドで別の1:

List<Point> list; 
if (!_dictionary.TryGetValue (pcost, out list)) 
{ 
    list = new List<Point>(); 
    dictionary.Add (pcost, list); 
} 
list.Add (new Point { X = n.x, Y = n.y }); 

が、これは.NETコンテナを使用しては不可能である理由を説明する何かがありますか?または、私はいくつかのポイントを逃したのですか?

ありがとうございました。

+1

のような素晴らしいトリックがたくさんあります。プロダクションコードでも2つのルックアップがありますか? – CodingBarfield

+0

デュアルルックアップは本当に重要ですか?時間の差はわずかです。 –

+4

@Chris:何? ) - 私はあなたが問題の場所にコードを表示することができます(ああ待って、_私は法的理由のためにすることはできません...) – sehe

答えて

-2

あなたはそのための拡張メソッドを作成することができます。

IDictionary<string, Point> _dictionary = GetDictionary(); 
_dictionary.GetOrAdd("asdf").Add(new Point(14, 15)); 

// ... elsewhere ... 
public static class DictionaryExtensions { 
    public static List<TValue> GetOrAdd<TKey, TValue>(this IDictionary<TKey, List<TValue>> self, TKey key) { 
     List<TValue> result; 
     self.TryGetValue(key, out result); 
     if (null == result) { 
      // the key value can be set to the null 
      result = new List<TValue>(); 
      self[key] = result; 
     } 

     return result; 
    } 
} 
+1

TValueが参照型であると仮定している場合は、代わりにTryGetValueの戻り値を確認する必要があります。 –

+3

これは今質問と同じコードですが、これで拡張が行われました。これはどのように役立ちますか?まだ2回の呼び出し、trygetvalueとadd。 – RvdK

+0

@PoweRoy:公平にするために、パフォーマンスは影響を受けています(正しい方向ではありません)。 – sehe

10

あなただけの、次の方法であなたの値を割り当てることができます。

var dict = new Dictionary<int, int>(); 
dict[2] = 11; 

キー2との値が存在しない場合 - それが追加されますさもなければそれはちょうど上書きされます。

辞書法GetOrAddを持っていませんが、C#4.0からConcurrentDictionaryが行われます。

var dict = new ConcurrentDictionary<int, int>(); 
dict[2] = 10; 
int a = dict.GetOrAdd(2, 11);// a == 10 
+0

優秀な情報、gorik – sehe

+0

@gorikあなたが示したような辞書は、キーが存在しない場合、例外をスローするでしょう – gerstla

+3

@amichai gerstlいいえ、それを試してください –

2

標準の一般的な辞書がこれをサポートしていない、2つのルックアップが必要です。ルックアップのコストは通常​​はごくわずかですが、これは問題ではなく、辞書検索をマイクロ最適化するのではなく、システムの他の部分をチューニングする方がより良い結果を得ることができます。

私が知っているこれをサポートする.netに付属する唯一の辞書はGetOrAddという方法でConcurrentDictionaryです。今はあなたが代わりに同期のコストを支払っています。

+0

false、この回答を確認してください:http://stackoverflow.com/a/16193323/893406 1つの検索のみ。 –

+1

@ v.oddou 'dict.Add'の呼び出しは内部的にルックアップを実行します。したがって、2つのルックアップが実行されます。 1つはTryGetValueで検索し、もう1つはAddで検索します。 –

+0

ahはい。邪悪な。 –

2

が、これは.NET コンテナを使用しては不可能である理由を説明するものはありますか?

実際の背景を知らないうちに、私はそれが辞書の簡潔さのためだと考えます。基本的でわかりやすい関数だけがあります:AddRemove a.s.oですが、インデックス演算子は多少直感的であると思われていました。

2

悲しいことに、bclの実装には1つもありません。最も近い選択肢は2つのルックアップをやっている、が、1つは、それが簡単にするために、一般的な拡張メソッドを持つことができ、as shown here

public static T GetOrAdd<S, T>(this IDictionary<S, T> dict, S key, 
           Func<T> valueCreator) 
{ 
    T value; 
    return dict.TryGetValue(key, out value) ? value : dict[key] = valueCreator(); 
} 

しかし、箱から出してこれを行いC5's implementationがあります。彼らはオブジェクトの作成を延期するFunc<V>の代わりVを受け入れない理由

public virtual bool FindOrAdd(K key, ref V value) 
{ 

} 

わからない。:メソッドの定義は次のようになります。C5には、例えば

public virtual bool Remove(K key, out V value) 

public virtual bool Update(K key, V value, out V oldvalue) 

public virtual bool UpdateOrAdd(K key, V value, out V oldvalue) 
関連する問題