众所周知,C#中的Dictionary在理论上不会保留插入元素的顺序。
出于枚举目的,字典中的每个项目都被视为代表值及其键的
KeyValuePair<TKey,TValue>
结构。物品的退还顺序是不确定的。
但是,当我将随机键插入字典并在foreach循环中读取它们时,它们总是按插入顺序返回。
Random rand = new Random();
var map = new Dictionary<int, int>();
for (int i = 0; i < 10; ++i)
{
var key = rand.Next(1000000000);
var value = 0;
Console.WriteLine($"Key: {key}");
if (map.ContainsKey(key))
continue;
map.Add(key,value);
}
Console.WriteLine("Reading Back..");
foreach (var pair in map)
{
Console.WriteLine($"Key: {pair.Key}");
}
此代码的输出如下:
Key: 593548784 Key: 765023454 Key: 1460074 Key: 913286745 Key: 804757753 Key: 281489700 Key: 395818098 Key: 227086287 Key: 323530161 Key: 629618868
回读..
Key: 593548784 Key: 765023454 Key: 1460074 Key: 913286745 Key: 804757753 Key: 281489700 Key: 395818098 Key: 227086287 Key: 323530161 Key: 629618868
我感到很惊讶,因为我以为当元素插入字典时,哈希键是通过取键字段的mod N来确定的,这意味着该顺序将丢失(除非N非常大)。
有人知道为什么这种行为吗?
答案 0 :(得分:3)
Dictionary
不支持排序的事实并不意味着您每次读取数据都会以随机顺序获得数据。通常,您将按照插入时的顺序对其进行遍历,但这是not guaranteed:
出于枚举目的,字典中的每个项目都被视为代表值及其键的KeyValuePair结构。 退回商品的顺序不确定。
当您开始删除,插入和添加其他条目时,原始订单可能会丢失。您可以在this question的答案中找到更多详细信息。
这是删除项目的示例代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace SO59038883
{
internal class Program
{
static void Main()
{
// keep track of the key that have been inserted
// so we can remove a random
var trackedKeys = new List<int>();
var rand = new Random();
var map = new Dictionary<int, int>();
for (var i = 0; i < 20; i++)
{
var key = rand.Next(1000000000);
trackedKeys.Add(key);
Console.WriteLine($"Key: {key}");
if (map.ContainsKey(key))
continue;
map.Add(key, i);
// Let's remove three random keys
// at set interval
if (i == 5 || i == 10 || i == 15)
{
// get a random key from our tracked key list
var index = rand.Next(trackedKeys.Count);
var keyToRemove = trackedKeys[index];
map.Remove(keyToRemove);
}
}
Console.WriteLine("Reading Back..");
foreach (var pair in map)
{
Console.WriteLine($"Key: {pair.Key} - Value: {pair.Value}");
}
if (Debugger.IsAttached)
{
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
}
答案 1 :(得分:2)
实现Dictionary
的方式不会将项目直接存储到哈希表中,而是使用整数哈希表,该哈希表随后用于标识增长数组中的项目。如果没有从Dictionary
中删除任何内容,则此数组将按添加顺序包含项目。从.NET开始,这种行为就一直是一致的。如果删除了项目,则将来的项目放置在数组中的顺序可能很难预测,我不希望它在所有.NET版本中都保持一致。