【发布时间】:2015-04-21 16:06:36
【问题描述】:
问题
必须循环遍历所有 C# Dictionary 元素只能通过 foreach 完成,如果是这样,为什么?
或者,我可以这样问:Dictionary 元素是否可以通过Dictionary 对象中的位置访问(即,first 元素,last 元素, 倒数第三个元素等)?
这个问题的背景
我正在尝试了解更多关于 Dictionary 对象如何工作的信息,所以如果能帮助我解决这个问题,我将不胜感激。我正在了解这一点,所以我有几个想法都与这个问题有关。我会尝试以适合 SO 格式的方式呈现。
研究
在 C# 数组中,元素按位置引用。在Dictionary 中,值由键引用。
翻看documentation on MSDN,有说法
"出于枚举的目的,字典中的每个项目都被视为 表示值及其键的 KeyValuePair 结构。这 返回项目的顺序未定义。”
因此,似乎由于返回的订单项是未定义的,因此无法按位置访问元素。我也读过:
"使用key取值非常快,接近O(1), 因为 Dictionary 类是作为哈希表实现的。”
查看HashTable .NET 4.5 class 的文档,参考了使用foreach 语句循环并返回元素。但是没有提及使用for 语句,或者就此而言while 或任何其他循环语句。
另外,我注意到Dictionary 元素使用IEnumerable 接口,它似乎使用foreach 作为循环函数的唯一语句类型。
想法
那么,这是否意味着Dictionary 元素不能像数组或列表那样通过“位置”访问?
如果是这样,为什么有一个 .Count 属性返回键/值对的数量,但没有任何东西可以让我通过接近总数来引用这些?比如.Count是5,为什么我不能请求键值对.Count减1?
foreach 如何能够遍历每个元素,但我无法以相同的方式访问单个元素?
如果不使用foreach,是否无法确定Dictionary 对象中元素(键或值)的位置?在没有将元素映射到集合的情况下,我不能判断一个键是Dictionary 中的第一个键还是最后一个键?
This SO question 和出色的答案都涉及到这一点,但我特别想看看我是否必须将元素复制到数组或其他可枚举类型,以按位置访问特定元素。
这是一个例子。请注意,我不是在寻找专门解决此示例的方法 - 这仅用于说明我的问题。假设我想将 Dictionary<string, string> 对象中的所有它们的键添加到逗号分隔的列表中,最后没有逗号。使用数组我可以做到:
string[] arrayStr = new string[2] { "Test1", "Test2" };
string outStr = "";
for (int i = 0; i < arrayStr.Length; i++)
{
outStr += arrayStr[i];
if (i < arrayStr.Length - 1)
{
outStr += ", ";
}
}
使用Dictionary<string, string>,如何使用上述方法将每个密钥复制到outStr?看来我必须使用foreach。但是存在哪些Dictionary 方法或属性可以让我在字典中识别元素的位置?
如果您仍在阅读本文,我还想指出,我并不是想说Dictionary 有什么错误...我只是想了解这是怎么回事.NET 框架中的工具的工作原理,以及如何最好地自己使用它。
【问题讨论】:
-
如果顺序很重要,请使用字典以外的其他集合类型,例如列表、堆栈、队列、数组或whathaveyou。当需要 O(1) 查找键=> 值时使用字典。例如,我不明白您为什么会对
"Count-1"'th 元素感兴趣;如果您是字典,则不是您要使用的集合类型。 -
顺序未定义,因此在特定索引处的值也未定义。我可以看到想要获取特定索引的唯一原因是随机访问元素,并且可能有更好的方法来做到这一点。
-
With Dictionary<string, string>, how would I copy each key to outStr using the above method?Presonally 我不会使用那种方法。var list = dictionary.Select(k => k.Key).ToList();更简单。 -
如果你有一个
strings的集合并且想要索引访问和散列查找,你可以使用NameValueCollection。但是没有通用版本(我一直想知道为什么)。 -
@Ulric,已经有一个
Keys属性;dictionary.Keys.ToList()更简单。