为什么c#dictionary foreach循环通常以与插入相同的顺序进行迭代
根据共同的真理和许多经过投票的答案,C#为什么c#dictionary foreach循环通常以与插入相同的顺序进行迭代,c#,dictionary,foreach,hashtable,C#,Dictionary,Foreach,Hashtable,根据共同的真理和许多经过投票的答案,C#字典在内部实现为哈希表,如果我有正确的理解,这意味着: foreach语句在字典项上的迭代顺序是不可预测的,因为在幕后,每个键都被散列,而底层数组中的索引都是根据该散列值分配的 如果我们想添加等于1,2,3,4,5,6,7的键,那么按什么顺序添加并不重要,因为与内部表示有关的唯一重要的事情是键的散列值 如果我以不同的顺序添加相同的键,那么在添加之后执行的foreach循环将以添加键的相同顺序迭代这些键,这怎么可能呢 这种行为背后有什么神奇的实现 我用于测试
字典
在内部实现为哈希表
,如果我有正确的理解,这意味着:
foreach
语句在字典项上的迭代顺序是不可预测的,因为在幕后,每个键都被散列,而底层数组中的索引都是根据该散列值分配的1,2,3,4,5,6,7的键,那么按什么顺序添加并不重要,因为与内部表示有关的唯一重要的事情是键的散列值
foreach
循环将以添加键的相同顺序迭代这些键,这怎么可能呢
这种行为背后有什么神奇的实现
我用于测试的代码片段:
static int[] x = { 3, 9, 5, 11, 12, 13, 2, 24, 137, 4, 1256, 67, 1, 125555 };
static void Main(string[] args)
{
//to avoid any rehashing and collisions issues the capacity is manually set to a value >> than the number of stored items
Dictionary<int, string> dict = new Dictionary<int, string>(10000);
for (int i = 0; i < x.Length; i++)
{
dict.Add(x[i], x[i].ToString());
}
Console.WriteLine("Foreaching element of dict after inserting from left to right\n");
foreach (var kvp in dict)//this displays items in exactly same order as they were added
{
Console.WriteLine(kvp.Key);
}
dict.Clear();
for (int i = x.Length - 1; i >= 0; i--)
{
dict.Add(x[i], x[i].ToString());
}
Console.WriteLine("Foreaching element of dict after inserting from right to left\n");
foreach (var kvp in dict)//this displays items in exactly same order as they were added
{
Console.WriteLine(kvp.Key);
}
}
static int[]x={3,9,5,11,12,13,2,24,137,41256,67,112555};
静态void Main(字符串[]参数)
{
//为避免任何重新灰化和冲突问题,手动将容量设置为大于存储项目数的值>>
Dictionary dict=新字典(10000);
对于(int i=0;i=0;i--)
{
dict.Add(x[i],x[i].ToString());
}
Console.WriteLine(“从右向左插入后的dict的foreatching元素\n”);
foreach(dict中的var-kvp)//这将以与添加项目完全相同的顺序显示项目
{
控制台写入线(kvp.Key);
}
}
这个问题部分与:
简言之,在内部,您可以在@Owen Pauling已经发布的源代码中查找的键
,值
,条目
,存储桶
很少
您应该最感兴趣的是private void Insert(TKey-key,TValue-value,bool-add)
方法,它是为add
调用的
在你问题的上下文中,有趣的部分是索引的计算,在你的例子中,它归结为index=count代码>。根据索引,将值添加到条目
集合中,并为适当的铲斗箱设置一个值
另一方面,在for
循环期间,使用枚举器
实现来初始化索引=0
和(在简单的情况下)只是在MoveNext
调用期间增加它。这意味着迭代是根据条目
集合完成的。因此,您可以在迭代期间观察与插入期间相同的顺序
如果有多个条目落入同一个bucket,那么流程可能会变得更复杂,但在您的示例中并非如此
注意:
请注意,上述描述仅适用于您正在介绍的案例。如果您尝试对字典进行一些修改,由于索引计算的流程略有不同,排序将被修改。例如,如果在显示关键点之前,您将:
dict.Remove(12);
dict.Add(15, "15");
新添加的键将取代先前删除的键,因为在Insert
方法中,您将陷入if(freeCount>0)
状态
此外,请记住不要依赖内部实现,因为除非明确记录,否则它可能会更改。您错了。哈希总是可以在正向(而不是反向)预测的。当前的实现具有这种副作用(但实现可以随时更改)。只要不删除项,它们将按添加顺序枚举。尝试删除一些项目,然后再添加一些。