我已经看到了几种不同的方法来迭代C#中的字典.有标准的方法吗?
foreach(KeyValuePair entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
如果您尝试在C#中使用通用字典,则可以使用另一种语言的关联数组:
foreach(var item in myDictionary) { foo(item.Key); bar(item.Value); }
或者,如果您只需要迭代密钥集合,请使用
foreach(var item in myDictionary.Keys) { foo(item); }
最后,如果您只对价值感兴趣:
foreach(var item in myDictionary.Values) { foo(item); }
(请注意,var
关键字是可选的C#3.0及以上功能,您也可以在此处使用键/值的确切类型)
在某些情况下,您可能需要一个可以通过for循环实现提供的计数器.为此,LINQ提供ElementAt
了以下功能:
for (int index = 0; index < dictionary.Count; index++) { var item = dictionary.ElementAt(index); var itemKey = item.Key; var itemValue = item.Value; }
取决于你是否在关键或价值观之后......
从MSDN Dictionary(TKey, TValue)
类描述:
// When you use foreach to enumerate dictionary elements, // the elements are retrieved as KeyValuePair objects. Console.WriteLine(); foreach( KeyValuePairkvp in openWith ) { Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value); } // To get the values alone, use the Values property. Dictionary .ValueCollection valueColl = openWith.Values; // The elements of the ValueCollection are strongly typed // with the type that was specified for dictionary values. Console.WriteLine(); foreach( string s in valueColl ) { Console.WriteLine("Value = {0}", s); } // To get the keys alone, use the Keys property. Dictionary .KeyCollection keyColl = openWith.Keys; // The elements of the KeyCollection are strongly typed // with the type that was specified for dictionary keys. Console.WriteLine(); foreach( string s in keyColl ) { Console.WriteLine("Key = {0}", s); }
一般来说,在没有特定背景的情况下询问"最好的方式"就像问什么是最好的颜色.
一方面,有很多颜色,没有最好的颜色.这取决于需要,也经常取决于口味.
另一方面,有许多方法可以在C#中迭代一个Dictionary,而且没有最好的方法.这取决于需要,也经常取决于口味.
最直截了当的方式foreach (var kvp in items) { // key is kvp.Key doStuff(kvp.Value) }
如果只需要值(允许调用它item
,比可读性更强kvp.Value
).
foreach (var item in items.Values) { doStuff(item) }如果您需要特定的排序顺序
通常,初学者对词典枚举的顺序感到惊讶.
LINQ提供了一种简洁的语法,允许指定顺序(以及许多其他内容),例如:
foreach (var kvp in items.OrderBy(kvp => kvp.Key)) { // key is kvp.Key doStuff(kvp.Value) }
您可能只需要该值.LINQ还提供了一个简洁的解决方案:
直接迭代值(允许调用它item
,更可读kvp.Value
)
但按键排序
这里是:
foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value)) { doStuff(item) }
您可以从这些示例中获得更多真实用例.如果您不需要特定订单,只需坚持"最直接的方式"(见上文)!
我会说foreach是标准的方式,虽然它显然取决于你在寻找什么
foreach(var kvp in my_dictionary) { ... }
这就是你要找的东西吗?
您也可以在大字典上尝试使用多线程处理.
dictionary .AsParallel() .ForAll(pair => { // Process pair.Key and pair.Value here });
我很欣赏这个问题已经有很多回复,但我想进行一些研究.
与迭代类似数组的东西相比,迭代字典可能会相当慢.在我的测试中,对数组的迭代花费了0.015003秒,而对字典的迭代(具有相同数量的元素)花费了0.0365073秒,这是2.4倍的长度!虽然我看到了更大的差异.为了进行比较,List介于0.00215043秒之间.
然而,这就像比较苹果和橘子.我的观点是迭代字典很慢.
字典针对查找进行了优化,因此考虑到这一点,我创建了两种方法.一个只是做一个foreach,另一个迭代键然后查找.
public static string Normal(Dictionarydictionary) { string value; int count = 0; foreach (var kvp in dictionary) { value = kvp.Value; count++; } return "Normal"; }
这个加载密钥并迭代它们(我也尝试将密钥拉成字符串[]但差别可以忽略不计.
public static string Keys(Dictionarydictionary) { string value; int count = 0; foreach (var key in dictionary.Keys) { value = dictionary[key]; count++; } return "Keys"; }
在这个例子中,正常的foreach测试花了0.0310062,密钥版本花了0.2205441.加载所有键并迭代所有查找显然要慢得多!
对于最后的测试,我已经执行了十次迭代,看看在这里使用密钥是否有任何好处(此时我只是好奇):
这是RunTest方法,如果这可以帮助您可视化正在发生的事情.
private static string RunTest(T dictionary, Func function) { DateTime start = DateTime.Now; string name = null; for (int i = 0; i < 10; i++) { name = function(dictionary); } DateTime end = DateTime.Now; var duration = end.Subtract(start); return string.Format("{0} took {1} seconds", name, duration.TotalSeconds); }
正常的foreach运行时间为0.2820564秒(大约是单次迭代的十倍 - 正如您所期望的那样).密钥的迭代花了2.2249449秒.
编辑添加: 阅读其他一些答案让我怀疑如果我使用词典而不是词典会发生什么.在此示例中,数组占用0.0120024秒,列表0.0185037秒,字典0.0465093秒.期望数据类型对字典的缓慢程度产生影响是合理的.
我的结论是什么?
如果可以的话,避免迭代字典,它们比在数组中使用相同数据进行迭代要慢得多.
如果你确实选择迭代字典,不要试图太聪明,虽然速度比使用标准的foreach方法要差很多.
有很多选择.我个人最喜欢的是KeyValuePair
DictionarymyDictionary = new Dictionary (); // Populate your dictionary here foreach (KeyValuePair kvp in myDictionary) { // Do some interesting things }
您还可以使用键和值集合
C#7.0引入了Deconstructors,如果您使用的是 .NET Core 2.0+应用程序,则该结构KeyValuePair<>
已经Deconstruct()
为您提供了一个。因此,您可以执行以下操作:
var dic = new Dictionary() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } }; foreach (var (key, value) in dic) { Console.WriteLine($"Item [{key}] = {value}"); } //Or foreach (var (_, value) in dic) { Console.WriteLine($"Item [NO_ID] = {value}"); } //Or foreach ((int key, string value) in dic) { Console.WriteLine($"Item [{key}] = {value}"); }
有了.NET Framework 4.7
一个可以使用的分解
var fruits = new Dictionary(); ... foreach (var (fruit, number) in fruits) { Console.WriteLine(fruit + ": " + number); }
要使此代码适用于较低的C#版本,请在System.ValueTuple NuGet package
某处添加和写入
public static class MyExtensions { public static void Deconstruct(this KeyValuePair tuple, out T1 key, out T2 value) { key = tuple.Key; value = tuple.Value; } }
您建议在下面进行迭代
DictionarymyDictionary = new Dictionary (); //Populate your dictionary here foreach (KeyValuePair kvp in myDictionary) { //Do some interesting things; }
foreach
如果值是object类型,则FYI 不起作用.
迭代字典的最简单形式:
foreach(var item in myDictionary) { Console.WriteLine(item.Key); Console.WriteLine(item.Value); }
使用C#7,将此扩展方法添加到解决方案的任何项目中:
public static class IDictionaryExtensions { public static IEnumerable<(TKey, TValue)> Tuples( this IDictionary dict) { foreach (KeyValuePair kvp in dict) yield return (kvp.Key, kvp.Value); } }
并使用这个简单的语法
foreach (var(id, value) in dict.Tuples()) { // your code using 'id' and 'value' }
或者这个,如果你愿意的话
foreach ((string id, object value) in dict.Tuples()) { // your code using 'id' and 'value' }
代替传统
foreach (KeyValuePairkvp in dict) { string id = kvp.Key; object value = kvp.Value; // your code using 'id' and 'value' }
扩展方法将KeyValuePair
您的变换转换IDictionary
为强类型tuple
,允许您使用这种新的舒适语法.
它将-just-所需的字典条目转换为tuples
,因此它不会将整个字典转换为tuples
,因此没有与此相关的性能问题.
tuple
与KeyValuePair
直接使用创建一个扩展方法相比,只需要很少的代价来调用扩展方法,如果你要分配KeyValuePair
的属性Key
和Value
新的循环变量,这应该不是问题.
在实践中,这种新语法非常适合大多数情况,除了低级超高性能方案,您仍然可以选择不在特定位置使用它.
看看这个:MSDN博客 - C#7中的新功能
有时,如果您只需要枚举值,请使用字典的值集合:
foreach(var value in dictionary.Values) { // do something with entry.Value only }
该帖子报道称这是最快的方法:http: //alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
我在MSDN上的DictionaryBase类的文档中找到了这个方法:
foreach (DictionaryEntry de in myDictionary) { //Do some stuff with de.Value or de.Key }
这是我能够在从DictionaryBase继承的类中正确运行的唯一一个.