これがここで尋ねる正しい質問かどうかはわかりませんが、私を殺さないでください:)
私は友人とC#の辞書について議論しています…彼女は私が持っているなら1つの要素を持つ辞書を言うことができると私に言います。キーのハッシュコードが100000の場合、辞書の内部配列は100000のサイズになります。
それは本当ですか?Googleで答えを見つけようとしましたが、何らかの理由でその質問が見つかりませんでした。
これがここで尋ねる正しい質問かどうかはわかりませんが、私を殺さないでください:)
私は友人とC#の辞書について議論しています…彼女は私が持っているなら1つの要素を持つ辞書を言うことができると私に言います。キーのハッシュコードが100000の場合、辞書の内部配列は100000のサイズになります。
それは本当ですか?Googleで答えを見つけようとしましたが、何らかの理由でその質問が見つかりませんでした。
MSDNによると、Dictionaryのデフォルトのコンストラクターは「デフォルトの初期容量を持っています」。
また、次のように述べています。
コレクションのサイズを見積もることができる場合は、初期容量を指定するコンストラクターを使用すると、ディクショナリに要素を追加するときに多数のサイズ変更操作を実行する必要がなくなります。
そのようなコンストラクターの1つは、単純にを取りますInt32
。これにより、内部ストレージが次のように初期化されます。
ディクショナリに含めることができる要素の初期数。
ディクショナリの「デフォルトの初期容量」とは、実際にはクラスの内部実装の詳細であり、ドキュメントやパブリックAPIには公開されていません。
デフォルトのコンストラクターを逆アセンブルmscorlib
しilspy
て調べると、次のように実装されていることがわかります。
public Dictionary() : this(0, null)
{
}
その連鎖コンストラクターは次のように実装されます。
public Dictionary(int capacity, IEqualityComparer<TKey> comparer)
{
if (capacity < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
}
if (capacity > 0)
{
this.Initialize(capacity);
}
this.comparer = (comparer ?? EqualityComparer<TKey>.Default);
}
つまりInitialize()
、直接または間接的に、デフォルトのコンストラクターによってまったく呼び出されません。
Initialize()
内部ストレージを設定する方法です。
したがって、実際には、デフォルトコンストラクターを呼び出すと、最初にアイテムを追加するまで、内部ストレージサイズは初期化されません。したがって、サイズは基本的にゼロです。
Initialize()
は、最初に呼び出すときに最終的にゼロの値で呼び出されます.Add()
。これにより、設定が行われます。
private void Initialize(int capacity)
{
int prime = HashHelpers.GetPrime(capacity);
this.buckets = new int[prime];
for (int i = 0; i < this.buckets.Length; i++)
{
this.buckets[i] = -1;
}
this.entries = new Dictionary<TKey, TValue>.Entry[prime];
this.freeList = -1;
}
GetPrime(0)
を返す3
ので、this.buckets
3つの整数を含む配列に設定されます。
に値を割り当てる行this.entries
は少し奇妙に見えますが、100000がこれに入る場所がわかりません。
簡単な答え
あなたの同僚は間違っていると思います。
ハッシュコード(つまりGetHashCode
)は、辞書が使用するバケットにアイテムを配置するために使用されます。
実際に使用される容量は、ディクショナリ内の要素の数に基づいています。
使用されるものの(おそらく正確ではない)擬似コードGetHashCode
はそのようなものです。
List<List<KeyValuePair<T,J>>> buckets; // let's assume this get's allocated somewhere (the dictionary allocates this internally)
...
public J GetValueFromDictionary(T key)
{
int bucketIndex = key.GetHashCode() % buckets.Length;
return buckets[bucketIndex].Find(x => x.Key == key).Single().Value;
}
いいえそうではありません。クラスの情報源はそれをDictionary<,>
証明しています。
リフレクターを使用してコードを逆コンパイルし、自分で検証するだけです。
辞書の保存はそれよりもはるかに複雑であるため、これはほとんど当てはまりません。さらに、キーとなる可能性のあるハッシュコードの値は、辞書のサイズを定義するものではありません(どのように作成できるかわかりません)。
それでは、辞書のストレージを分解してみましょう。
オブジェクトがディクショナリのキーとして使用されている限り、そのハッシュ値に影響を与えるような方法でオブジェクトを変更してはなりません。ディクショナリ内のすべてのキーは、ディクショナリの等値比較器に従って一意である必要があります。キーをnull参照(Visual BasicではNothing)にすることはできませんが、値型TValueが参照型の場合は、値をnull参照にすることができます。
ディクショナリでは、キーが等しいかどうかを判断するために等式の実装が必要です。比較パラメーターを受け入れるコンストラクターを使用して、IEqualityComparerジェネリックインターフェイスの実装を指定できます。実装を指定しない場合は、デフォルトのジェネリック等式比較子EqualityComparer.Defaultが使用されます。タイプTKeyがSystem.IEquatableジェネリックインターフェイスを実装している場合、デフォルトの等式比較プログラムはその実装を使用します。
次のように定義されているため、ハッシュコードが使用される可能性があります。EqualityComparer.Default
Defaultプロパティは、タイプTがSystem.IEquatableジェネリックインターフェイスを実装しているかどうかをチェックし、実装している場合は、その実装を使用するEqualityComparerを返します。それ以外の場合は、Tによって提供されるObject.EqualsおよびObject.GetHashCodeのオーバーライドを使用するEqualityComparerを返します。
キーがどのように生成されるかは、決して保証されません。だから、これがあなたの議論に役立つことを願っています。
結論として、ハッシュコードが辞書の内部サイズを決定する方法はありません。辞書は変更可能であり、Microsoftが述べているように、アイテムが追加されるにつれて大きくなります。
ディクショナリの容量は、ディクショナリが保持できる要素の数です。要素がディクショナリに追加されると、内部配列を再割り当てすることにより、必要に応じて容量が自動的に増加します。
あなたの友人は議論する前に彼女の研究をする必要があります。ふぅ!
更新として、Microsoftは.NET実装の参照コードを提供します。これにより、逆コンパイルを実行するよりも簡単になります。特にこの質問については、を参照してください
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs https://referencesource.microsoft.com/#mscorlib/system/collections/hashtable.cs
前の回答で述べたように、デフォルトの容量は3であることがわかります。
いいえ、これは真実ではありません。私が持っている場合
Dictionary<int, object[]> dict = new Dictionary<int, object[]>()
{
{10000, new object[] { 1, 2, 3, 4 }}
};
このディクショナリには、上記で入力したオブジェクトが後に続く9999個の空のオブジェクト配列スロットではなく、インデックスが10000の1つのオブジェクト配列が含まれます。答えはノーです、あなたの友達は間違っています。
これがお役に立てば幸いです。