11

TKey が int のペアであるディクショナリを使用する必要があります。

キーのタイプに KeyValuePair を使用することを考えましたが、これが最善の方法であるかどうか疑問に思っていました

また、ディクショナリが同じ ints を持つ 2 つの異なる KeyValuePair オブジェクトに対して個別のエントリを作成するかどうか、およびその理由を知りたいです。

例えば:

var myDictionary = new Dictionary<KeyValuePair<int,int>, string>();
myDictionary.Add(new KeyValuePair<int,int>(3, 3), "FirstItem");
myDictionary.Add(new KeyValuePair<int,int>(3, 3), "SecondItem");
// does the dictionary allow this?
4

6 に答える 6

29

多分あなたはTuple

var myDictionary = new Dictionary<Tuple<int,int>, List<string>>(); 
myDictionary.Add(new Tuple<int,int>(3, 3), "FirstItem"); 
myDictionary.Add(new Tuple<int,int>(5, 5), "SecondItem"); 

MSDN のドキュメントによると、TupleオブジェクトEqualsメソッドは 2 つのオブジェクトの値を使用しTupleます。これによりTuple、外部ディクショナリごとに 1 つのエントリが作成され、キーごとに値のリストを保存できます。

于 2012-09-24T18:09:21.217 に答える
10

asキーを使用して2つのキーlongを組み合わせるだけですint

public class IntIntDict<T> : Dictionary<long, T>
{
    public void Add(int key1, int key2, T value)
    {
        Add((((long)key1) << 32) + key2, value);
    }

    //TODO: Overload other methods
}

アップデート

C# 7 では、単純化されたタプル構文と共に、新しいValueTuple Structが導入されています。これらのタプルは、複合キーに役立ちます。辞書を宣言して、次のようにエントリを追加できます。

var myDictionary = new Dictionary<(int, int), string>();
myDictionary.Add((3, 3), "FirstItem"); 
myDictionary.Add((5, 5), "SecondItem");

このような値を調べます

string result = myDictionary[(5, 5)];

また

if (myDictionary.TryGetValue((5, 7), out string result)) {
    //TODO: use result
}
于 2012-10-01T13:58:23.973 に答える
6

パフォーマンスのために、Dictionary には一意の GetHashValue を生成するキーが必要です。

KeyValuePair は値の型であり、キーにはお勧めしません。

ValueType.GetHashCode

派生型の GetHashCode メソッドを呼び出す場合、戻り値はハッシュ テーブルのキーとして使用するのに適していない可能性があります。さらに、これらのフィールドの 1 つ以上の値が変更されると、戻り値がハッシュ テーブルのキーとして使用できなくなる可能性があります。いずれの場合も、型のハッシュ コードの概念をより厳密に表す GetHashCode メソッドの独自の実装を作成することを検討してください。

ポイントも値型であり、キーにも推奨されません。
タプルも多くの重複する GetHashCode を生成し、適切なキーではありません。

最適なキーは、一意のキーを生成するキーです。

UInt16 i と UInt j を 2 つのキーと考えてください。
それらをどのように組み合わせて一意のハッシュを生成できますか?
それらをUInt32に簡単に結合します。
UInt32 は完全なハッシュをネイティブに生成します。

2 つの UInt16 を UInt32 にパックするアルゴリズムは次のとおりです。

(i * (UInt16.MaxValue + 1)) + j;

しかし、それはさらに高速です

(UInt32)i << 16 | j;


myDictionary = new Dictionary<UInt32, string>();

完全なハッシュでは、辞書は O(1) です。
不十分なハッシュでは、Dictionary は O(n) になります。

于 2012-09-24T18:17:03.197 に答える
0

ディクショナリには、キーが等しいかどうかを判断するための等価実装が必要です。IEqualityComparer<T>比較パラメーターを受け入れるコンストラクターを使用して、ジェネリック インターフェイスの実装を指定できます。実装を指定しない場合は、デフォルトの汎用等値比較子EqualityComparer<T>.Defaultが使用されます。

したがって、あなたの場合、指定しないためIEqualityComparer<T>、デフォルトが使用されます。

EqualityComparer<T>.Default、型 T がインターフェイスを実装しているかどうかをチェックし、実装System.IEquatable<T>している場合は、その実装を使用する EqualityComparer を返します。それ以外の場合は、 T によって提供されるおよびEqualityComparer<T>のオーバーライドを使用する を返します。Object.EqualsObject.GetHashCode

T は structKeyValuePairを実装していないので、struct のandメソッドをSystem.IEquatable<T>使用します。これらの 2 つのメソッドは、 と の両方を使用して等しいかどうかをチェックし、ハッシュ コードを生成します。EqualGetHashCodeKeyValuePairKeyValue

public override int GetHashCode()
{
    return Key.GetHashCode() ^ Value.GetHashCode();
}

したがって、要約すると、サンプル辞書では許可されていません。

于 2012-09-24T18:46:13.473 に答える
0

更新: 他のレスポンダーへのコメントに基づいて、以下のコードが質問に答えます。はい、重複すると例外 System.ArgumentException が生成されます

リストしたコードは機能しますが、重複する KeyValuePairs は受け入れません。辞書に既に存在する KeyValuePair を追加すると、System.ArgumentException などがスローされます。

たとえば、このコード

using System;
using System.Collections;
using System.Collections.Generic;

namespace test{

    public class App {

        public static void Main(string[] args) {
            var myDictionary = new Dictionary<KeyValuePair<int,int>, string>(); 

            Console.WriteLine("Adding 2 items...");
            myDictionary.Add(new KeyValuePair<int,int>(3, 3), "FirstItem"); 
            myDictionary.Add(new KeyValuePair<int,int>(5, 5), "SecondItem"); 
            Console.WriteLine("Dictionary items: {0}", myDictionary.Count);

            Console.WriteLine("Adding 2 duplicate items...");
            myDictionary.Add(new KeyValuePair<int,int>(3, 3), "FirstItem"); 
            myDictionary.Add(new KeyValuePair<int,int>(5, 5), "SecondItem"); 
            Console.WriteLine("Dictionary items: {0}", myDictionary.Count);
        }
    }
}

以下を与える

Microsoft (R) Visual C# Compiler バージョン 4.0.30319.17626 for Microsoft (R) .NET Framework 4.5 Copyright (C) Microsoft Corporation. 全著作権所有。

2 つのアイテムを追加しています... 辞書アイテム: 2 2 つの重複したアイテムを追加しています...

未処理の例外: System.ArgumentException: 同じキーを持つ項目が既に追加されています。System.Collections.Generic.Dictionary`2.Insert (TKey キー、TValue 値、ブール値の追加) で、test.App.Main (String [] args) で

于 2012-09-24T18:18:08.390 に答える
-1

辞書のキーとしてKeyValuePairを使用する:

KeyValuePairを辞書のキーとして使用することは機能的に機能します。ただし、2つのint間のキーと値の関係を意味するため、概念的にはアプリケーションにとっておそらく最良の選択ではありません。

代わりに、マイクが提案するように、キーにはタプルを使用する必要があります。

2番目の質問の場合:

var myDictionary = new Dictionary<KeyValuePair<int,int>, string>();  
myDictionary.Add(new KeyValuePair<int,int>(3, 3), "FirstItem");  
myDictionary.Add(new KeyValuePair<int,int>(3, 3), "SecondItem");  
// does the dictionary allow this?  

ディクショナリはこれを許可しません。ディクショナリ自体は、キーが一意である必要があるキーと値のペアのセットです。複数の値を同じキーにマップできるようにする場合、1つのオプションは、値を別のコレクションにすることです。

var myDictionary = new Dictionary<KeyValuePair<int,int>, List<string>>();  

ただし、例のようにmyDictionary.Addを使用することはできません。代わりに、キーが辞書の一部であるかどうかを判断し、それに応じて動作するための追加機能を提供する必要があります。

public static class DictionaryHelper
{

    public static void Add(this Dictionary<Tuple<int,int>, List<string>> dict,Tuple<int,int> key, string value)
    {
        if(dict.ContainsKey(key))
        {
            dict[key].Add(value);
        }
        else
        {
            dict.Add(key, new List<string>{value});
        }
    } 
}
于 2012-09-24T18:31:09.460 に答える