在C#中迭代字典的最佳方法是什么?

我已经看到了几种不同的方式来遍历C#中的字典。 有没有标准的方法?

 foreach(KeyValuePair<string, string> entry in myDic) { // 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及以上版本的function,您也可以在这里使用您的键/值的确切types)

在某些情况下,您可能需要一个可能由for循环实现提供的计数器。 为此,LINQ提供了ElementAt ,它可以实现以下function:

 for (int index = 0; index < dictionary.Count; index++) { var item = dictionary.ElementAt(index); var itemKey = item.Key; var itemValue = item.Value; } 

取决于你是在键或值之后…

从MSDN Dictionary <(Of <(TKey,TValue>)>)类说明:

 // When you use foreach to enumerate dictionary elements, // the elements are retrieved as KeyValuePair objects. Console.WriteLine(); foreach( KeyValuePair<string, string> kvp in openWith ) { Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value); } // To get the values alone, use the Values property. Dictionary<string, string>.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<string, string>.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) } 

如果您需要特定的sorting顺序

一般来说,初学者对字典的枚举顺序感到惊讶。

LINQ提供了一个简洁的语法,允许指定顺序(和许多其他的东西),例如:

 foreach (var kvp in items.OrderBy(kvp => kvp.Key)) { // key is kvp.Key doStuff(kvp.Value) } 

再次,你可能只需要价值。 LINQ还提供了一个简洁的解决scheme:

  • 直接迭代该值(允许调用它的item ,比kvp.Value更具可读性)
  • 但按键sorting

这里是:

 foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value)) { doStuff(item) } 

从这些例子中你可以做更多的现实世界的用例。 如果你不需要特定的订单,只要坚持“最直接的方式”(见上文)!

我会说foreach是标准的方式,但显然取决于你在找什么

 foreach(var value in my_dictionary) { ... } 

那是你在找什么?

有很多select。 我个人最喜欢的是KeyValuePair

 Dictionary<string,object> myDictionary = new Dictionary<string,object>(); //Populate your dictionary here Foreach (KeyValuePair<string,object> kvp in myDictionary) { //Do some interesting things; } 

您也可以使用键和值集合

您也可以在大字典上尝试multithreading处理。

 dictionary .AsParallel() .ForAll(pair => { // Process pair.Key and pair.Value here }); 

我很欣赏这个问题已经有了很多的回应,但是我想投入一点研究。

与迭代类似数组的东西相比,迭代字典可能相当慢。 在我的testing中,对一个数组的迭代需要0.015003秒,而对字典(具有相同数量的元素)的迭代需要0.0365073秒,这是2.4倍的时间! 虽然我看到了更大的差异。 比较而言,List是在0.00215043秒之间。

然而,这就像比较苹果和橘子。 我的意思是迭代字典很慢。

字典为查找进行了优化,所以考虑到这一点,我创build了两种方法。 一个简单的foreach,另一个迭代键,然后查找。

  public static string Normal(Dictionary<string, string> dictionary) { string value; int count = 0; foreach (var kvp in dictionary) { value = kvp.Value; count++; } return "Normal"; } 

这个加载的密钥,而不是迭代(我也试着把钥匙拉到一个string[],但差异是微不足道的。

  public static string Keys(Dictionary<string, string> dictionary) { string value; int count = 0; foreach (var key in dictionary.Keys) { value = dictionary[key]; count++; } return "Keys"; } 

在这个例子中,普通的foreachtesting花费了0.0310062,而关键字花费了0.2205441。 加载所有的键和遍历所有的查找显然是很慢很多!

对于最后的testing,我已经执行了十次迭代,看看在这里使用密钥是否有任何好处(这一点我只是好奇):

如果这可以帮助你可视化发生的事情,这里是RunTest方法。

  private static string RunTest<T>(T dictionary, Func<T, string> 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秒。 期望数据types对字典的速度有多大的影响是有道理的。

我的结论是什么?

  • 如果可以的话,避免迭代字典,它们比迭代数组中的数据要慢得多。
  • 如果你select迭代一个字典,不要试图太聪明,尽pipe比使用标准的foreach方法要慢一些。

你在下面build议迭代

 Dictionary<string,object> myDictionary = new Dictionary<string,object>(); //Populate your dictionary here foreach (KeyValuePair<string,object> kvp in myDictionary) { //Do some interesting things; } 

仅供参考,如果值是types对象,则foreach不起作用。

最简单的forms来迭代一个字典:

 foreach(var item in myDictionary) { Console.WriteLine(item.Key); Console.WriteLine(item.Value); } 

有时,如果您只需要枚举值,请使用字典的值集合:

 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类的文档中find了这个方法:

 foreach (DictionaryEntry de in myDictionary) { //Do some stuff with de.Value or de.Key } 

这是我从一个从DictionaryBaseinheritance的类中能够正常工作的唯一一个。

我将利用.NET 4.0+的优势,并为最初接受的答案提供一个更新的答案:

 foreach(var entry in MyDic) { // do something with entry.Value or entry.Key } 

根据MSDN上的官方文档,遍历字典的标准方法是:

 foreach (DictionaryEntry entry in myDictionary) { //Read entry.Key and entry.Value here } 

如果说,你想默认迭代值集合,我相信你可以实现IEnumerable <>,其中T是字典中的值对象的types,而“this”是一个字典。

 public new IEnumerator<T> GetEnumerator() { return this.Values.GetEnumerator(); } 

只是想添加我的2美分,因为大多数答案涉及到foreach循环。 请看下面的代码:

 Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>(); //Add some entries to the dictionary myProductPrices.ToList().ForEach(kvP => { kvP.Value *= 1.15; Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value)); }); 

Altought增加了一个“.ToList()”的额外的调用,可能会有一些性能改进(正如foreach vs someList.Foreach(){} )所指出的那样,特别是在使用大型字典并且并行运行时选项/根本不会有效果。

另外,请注意,您将无法将值分配给foreach循环内的“Value”属性。 另一方面,你也可以操纵'钥匙',也可能在运行时遇到麻烦。

当您只想“读取”键和值时,也可以使用IEnumerable.Select()。

 var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } ); 
 var dictionary = new Dictionary<string, int> { { "Key", 12 } }; var aggregateObjectCollection = dictionary.Select( entry => new AggregateObject(entry.Key, entry.Value)); 

不是标准的方式,而是工作:

 Dictionary<string, int> dict = new Dictionary<string, int> { {"Foo", 1 }, {"Bar", 2 } }; dict.Select(kvp => { Console.WriteLine(kvp.Key + " - " + kvp.Value.ToString()); return kvp; }).Count(); 

使用.NET Framework 4.7可以使用分解

 var fruits = new Dictionary<string, int>(); ... foreach (var (fruit, number) in fruits) { Console.WriteLine(fruit + ": " + number); } 

为了使这个代码在较低的C#版本上工作,添加System.ValueTuple NuGet package并写入某处

 public static class MyExtensions { public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value) { key = tuple.Key; value = tuple.Value; } }