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

评论

令我惊讶的是,这个问题有很多答案,还有923次被推荐。(我用它讲授课程)..我认为,或者至少要补充一点,如果您必须遍历一本字典,那么您很可能是我不得不发表此评论,因为我看到字典以不恰当的方式被滥用,恕我直言……是的,在少数情况下,当您迭代字典而不是查找字典时,情况就是如此它是为...而设计的。请记住这一点,然后再想知道如何遍历字典。

@VikasGupta当您不知道键将是什么时,您会建议如何使用一组键值对来做某事?

@displayName如果您想对每个键-值对执行某项操作,但没有对用于查找值的键的引用,则可以遍历字典,对吗?我只是指出,尽管维卡斯(Vikas)声称这通常是不正确的用法,但有时您还是想这样做。

要说它的用法不正确,意味着有更好的选择。那有什么选择呢?

VikasGupta是错误的,我可以肯定地说,经过多年在非理论性场景下的高性能C#和C ++编程之后。实际上,确实经常发生这样的情况:创建字典,存储唯一的键值对,然后迭代这些值,事实证明,这些值在集合中具有唯一的键。创建任何其他集合是避免字典迭代的一种非常低效且成本很高的方法。请提供一个很好的选择,作为对问题的回答,以阐明您的观点,否则您的评论就太荒谬了。

#1 楼

 foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}
 


评论


如果我不完全了解字典中键/值的类型怎么办。在这种情况下,使用var entry更好,因此,我确实在第二张表上而不是上面的表中投票了此答案。

– Ozair Kafray
16年1月5日在7:32

@OzairKafray在您不知道类型时通常使用var,这是不好的做法。

–内特
16 Jan 25'23:34



这个答案是优越的,因为Pablo没有默认使用混淆返回类型的惰性编码器“ var”。

–MonkeyWrench
16年5月17日在17:19

@MonkeyWrench:嗯。 Visual Studio知道类型是什么。您所要做的就是将鼠标悬停在变量上以进行查找。

–罗伯特·哈维(Robert Harvey)
16 Dec 9'在18:30



据我了解,只有在编译时知道类型的情况下,var才起作用。如果Visual Studio知道类型,那么您也可以找到它。

–凯尔·德莱尼(Kyle Delaney)
17年9月21日在13:06

#2 楼

如果您尝试在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及更高版本的可选功能,您也可以在此处使用键/值的确切类型)

评论


第一个代码块最需要var功能:)

– nawfal
2013年11月1日14:26

我很欣赏这个答案指出您可以显式地遍历键或值。

–Rotsiser Mho
15年1月13日在6:17

我不喜欢在这里使用var。鉴于它只是语法糖,为什么在这里使用它?当某人尝试阅读代码时,他们将不得不在代码周围跳转以确定myDictionary的类型(除非这是课程的实际名称)。我认为当类型很明显时使用var很好,例如var x =“ some string”,但是当它不是立即显而易见时,我认为这是惰性编码,会损害代码阅读器/查看器

–詹姆斯·维尔茨巴(James Wierzba)
17年1月25日在17:23



我认为var应该谨慎使用。特别是在这里,它不是建设性的:KeyValuePair类型可能与问题有关。

–辛加
17年8月21日在16:21

var具有独特的用途,我不认为这是“句法”糖。有目的地使用它是一种适当的方法。

–约书亚K
18年9月7日在18:43

#3 楼

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

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


评论


要使用'.ElementAt'方法,请记住:using System.Linq;在fx中不包含此功能。自动生成的测试类。

–蒂尼亚
2011年11月24日14:47



如果要修改与键相关联的值,这就是方法。否则,在修改和使用foreach()时会引发异常。

–迈克·德·克莱克(Mike de Klerk)
13年4月3日在7:18

ElementAt不是O(n)运算吗?

– Arturo TorresSánchez
2015年2月7日,下午1:46

这个答案是完全不值得的。字典没有隐式顺序,因此在此上下文中使用.ElementAt可能会导致细微的错误。更严重的是阿图罗的观点。您将迭代字典dictionary.Count + 1次导致O(n ^ 2)复杂度仅为O(n)的操作。如果您确实需要索引(如果确实需要索引,那么您可能首先使用了错误的集合类型),则应该迭代dictionary.Select((kvp,idx)=> new {Index = idx,kvp.Key, kvp.Value}),而不在循环内使用.ElementAt。

–spender
2015年3月2日在2:17



ElementAt-o(n)操作!认真吗这是不应执行此操作的示例。有这么多投票?

– Mukesh Adhvaryu
16年5月12日在22:14

#4 楼

取决于您要使用的是键还是值...

来自MSDN Dictionary(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);
}


#5 楼

通常,在没有特定上下文的情况下要求“最佳方式”就像问
什么是最好的颜色?

一方面,有很多颜色,没有最好的颜色。

另一方面,有很多方法可以在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)
}


您可以从这些示例中获得更多实际使用案例。
如果不这样做需要特定的顺序,只需坚持“最直接的方法”(请参见上文)!

评论


最后一个应该是.Values而不是select子句。

–Mafii
16-09-23在10:05

@Mafii您确定吗? OrderBy返回的值不是KeyValuePair类型,它们没有值字段。我在这里看到的确切类型是IOrderedEnumerable >。也许您还有其他意思?您可以写完整的行来显示您的意思(并进行测试)吗?

–StéphaneGourichon
16-09-23在14:30

我认为这个答案包含了我的意思:stackoverflow.com/a/141105/5962841但是如果我感到困惑,请纠正我

–Mafii
16-09-23在14:34

@Mafii重新阅读我的全部答案,代码段之间的解释说明了上下文。您提到的答案就像我答案中的第二个代码部分(无需订购)。在那里,我只是写了items.Value,就像您建议的那样。对于您评论的第四部分,Select()是一种使foreach直接枚举字典中的值而不是键值对的方法。如果在某种情况下您不喜欢Select(),则可能更喜欢第三个代码部分。第四部分的重点是表明可以使用LINQ对集合进行预处理。

–StéphaneGourichon
16-09-23在15:14

如果执行.Keys.Orderby(),则将迭代键列表。如果这就是您所需要的,那就好。如果需要值,则在循环中,您必须查询每个键上的字典以获取值。在许多情况下,它并没有什么实际意义。在高性能方案中,它将。就像我在答案开头写道:“有很多方法(...),没有最好的方法。这取决于需求,通常也取决于味道。”

–StéphaneGourichon
16-09-23在15:23



#6 楼

我会说foreach是标准方法,尽管它显然取决于您要查找的内容

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


您正在寻找的是什么?

#7 楼

C#7.0引入了Deconstructors,如果您使用的是.NET Core 2.0+应用程序,则结构KeyValuePair<>已经为您提供了Deconstruct()。因此,您可以执行以下操作:

var dic = new Dictionary<int, string>() { { 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.2或更高版本的KeyValuePair上没有解构,请尝试以下操作:dic.Select(x =>(x.Key,x.Value)中的foreach(var(键,值) )))

–nwsmith
19-4-26在11:58



#8 楼

您也可以在大型字典上尝试进行多线程处理。

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


评论


@WiiMaxx,如果这些项目彼此不依赖,则更重要

–Mafii
16-09-23在10:07

#9 楼

我很高兴这个问题已经得到了很多答复,但是我想进行一些研究。

与字典相比,对字典进行迭代可能会比较慢。在我的测试中,数组上的迭代花费了0.015003秒,而字典(具有相同数量的元素)上的迭代花费了0.0365073秒,是其两倍的时间!尽管我看到了更大的差异。为了进行比较,列表在0.00215043秒之间。

但是,这就像比较苹果和桔子。我的观点是对字典进行迭代很慢。

字典针对查找进行了优化,因此考虑到这一点,我创建了两种方法。一个简单地做一个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";
}


此示例加载按键并对其进行迭代(我也尝试过拉动按键)

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";
}


在此示例中,正常的foreach测试使用0.0310062,而密钥版本使用0.2205441。加载所有密钥并进行迭代在所有查找过程中显然要慢很多!

对于最终测试,我已经执行了十次迭代,以查看在此处使用键是否有任何好处(到目前为止,我只是很好奇):

如果可以帮助您直观地了解发生的情况,请使用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);
}


此处,正常的每次运行耗时0.2820564秒(大约比一次迭代要花十倍的时间-正如您所期望的那样。键上的迭代花了2.2249449秒。

编辑添加:
阅读其他一些答案使我怀疑如果我使用Dictionary而不是Dictionary会发生什么。在此示例中,数组花费0.0120024秒,列表花费0.0185037秒,字典花费0.0465093秒。可以合理预期数据类型会影响字典的运行速度。

我的结论是什么?


如果出现以下情况,请避免对字典进行迭代:您可以,它们比在具有相同数据的数组上迭代要慢得多。
如果您选择对字典进行迭代,则不要尝试太聪明,尽管慢些可能比在字典上做得差得多使用标准的foreach方法。


评论


您应该使用StopWatch之类的东西而不是DateTime进行测量:hanselman.com/blog/…

–连面
2015年2月23日在19:26

您能否描述一下您的测试场景,词典中有多少项,您运行场景多长时间来计算平均时间,...

– WiiMaxx
15年7月29日在8:57

有趣的是,根据字典中包含的数据,您将获得不同的结果。在字典上进行迭代时,枚举器函数必须跳过字典中的许多空插槽,这是导致其慢于在数组上进行迭代的原因。如果字典已满,则要跳过的空插槽要少于一半的空插槽。

–马丁·布朗
16年6月30日在8:36

#10 楼

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

Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     // Do some interesting things
}


您还可以使用键和值集合

评论


赞成这一点..并赞赏“ var”的非使用。我讨厌其中带有“ var”的代码示例。除非它是“ var emp = new Employee()” ...否则一个人根本不知道var是什么。谢谢。

– granadaCoder
7月24日15:05

@granadaCoder如果没人能告诉我什么是var,那么您的命名方式不正确

– Eonasdan
9月14日下午14:21

#11 楼

使用.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;
    }
}


评论


这是不正确的。 .NET 4.7只是内置了ValueTuple。它可以作为nuget包用于早期版本。更重要的是,需要使用C#7.0+才能使Deconstruct方法用作水果中var(水果,数字)的解构函数。

– David Arno
17-10-18在11:58

#12 楼

从C#7开始,您可以将对象解构为变量。我相信这是迭代字典的最佳方法。

示例:

KeyValuePair<TKey, TVal>上创建解构它的扩展方法:

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
   key = pair.Key;
   value = pair.Value;
}


以下列方式遍历任何Dictionary<TKey, TVal>

// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();

// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
   Console.WriteLine($"{key} : {value}");
}


评论


即使没有解构扩展方法,for循环也可以工作

– VCK
9月23日12:35

#13 楼

您在下面建议了对

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}


FYI进行迭代,如果值是object类型,则foreach不起作用。

评论


请详细说明:如果哪个值是object类型,foreach将不起作用?否则,这没有什么意义。

– Marc L.
17年12月29日在16:22

#14 楼

正如已经在此答案中指出的那样,KeyValuePair<TKey, TValue>从.NET Core 2.0,.NET Standard 2.1和.NET Framework 5.0(预览版)开始实现了Deconstruct方法。

可以通过以不可知的方式在字典中:

var dictionary = new Dictionary<int, string>();

// ...

foreach (var (key, value) in dictionary)
{
    // ...
}


#15 楼

迭代字典的最简单形式:

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


#16 楼

使用C#7,将此扩展方法添加到解决方案的任何项目中:

public static class IDictionaryExtensions
{
    public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
        this IDictionary<TKey, TValue> dict)
    {
        foreach (KeyValuePair<TKey, TValue> 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 (KeyValuePair<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}



扩展方法将KeyValuePairIDictionary<TKey, TValue>转换为强类型的tuple,使您可以使用这种新的舒适语法。

它将转换-just-将必需的字典条目转换为tuples,因此它不会将整个字典转换为tuples,因此不存在与此相关的性能问题。

只有很少的成本调用扩展方法与直接使用tuple相比,创建KeyValuePair仍然是一个问题,如果您仍要将KeyValuePair的属性KeyValue分配给新的循环变量,则应该没问题。很好在大多数情况下,除了低级超高性能方案外,您仍然可以选择不直接在特定位置使用它。

请查看以下内容:MSDN博客-C#7中的新功能

评论


为什么选择“舒适的”元组而不是键值对的原因是什么?我在这里看不到收获。您的元组包含一个键和一个值,键-值对也是如此。

–马丁
18/09/10在12:57

嗨,马丁(Maarten),谢谢您的提问。主要优点是无需额外的编程工作即可读取代码。使用KeyValuePair时,必须始终使用kvp.Key和kvp.Value形式分别使用键和值。使用元组,您可以灵活地根据需要命名键和值,而无需在foreach块内使用其他变量声明。例如。您可以将键命名为factoryName,将值命名为model,这在获取嵌套循环(字典的字典)时特别有用:代码维护变得更加容易。试一试! ;-)

–sɐunıɔןɐqɐp
18/09/10在13:49



#17 楼

foreach最快,如果仅迭代___.Values,它也更快。



评论


为什么要在for版本中调用ContainsKey()?这增加了您要比较的代码中不存在的额外开销。存在TryGetValue()来替换确切的“如果键存在,则用键获取项目”模式。此外,如果dict包含从0到dictCount-1的连续整数范围,则您知道索引器不会失败;否则,dict.Keys应该是您要迭代的。无论哪种方式,都不需要ContainsKey()/ TryGetValue()。最后,请不要发布代码的屏幕截图。

–培根
4月29日18:55

#18 楼

我知道这是一个非常老的问题,但是我创建了一些可能有用的扩展方法:

    public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
    {
        foreach (KeyValuePair<T, U> p in d) { a(p); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
    {
        foreach (T t in k) { a(t); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
    {
        foreach (U u in v) { a(u); }
    }


这样我可以编写如下代码:

myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););


#19 楼

我在MSDN上的DictionaryBase类的文档中找到了这种方法:

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


这是我唯一能够在继承自MSDN的类中正常运行的方法。 DictionaryBase。

评论


这看起来像在使用非通用版本的Dictionary ...,即.NET Framework 2.0之前的版本。

– joedotnot
2014年4月26日在13:21

@ joed0tnot:这是用于Hashtable对象的非泛型版本

–sɐunıɔןɐqɐp
18年8月1日在19:42



#20 楼

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

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

评论


+1可以提高性能。确实,如果只需要值,对字典本身进行迭代确实会带来一些开销。这主要是由于将值或引用复制到KeyValuePair结构中。

–Jaanus Varus
15年8月5日在10:25

仅供参考,该链接中的最后一个测试是测试错误的东西:它测量对键的迭代,而不考虑值,而前两个测试确实使用值。

–新月鲜
18年7月13日在14:15

#21 楼

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

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


#22 楼

根据MSDN上的官方文档,迭代词典的标准方法是:

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


#23 楼

如果说,您想默认情况下遍历值集合,我相信您可以实现IEnumerable <>,其中T是字典中value对象的类型,而“ this”是Dictionary。

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


#24 楼

我写了一个扩展来遍历字典。

public static class DictionaryExtension
{
    public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
        foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
            action(keyValue.Key, keyValue.Value);
        }
    }
}


然后您可以致电

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));


评论


您定义了一个ForEach方法,其中有foreach(...){} ...似乎不必要。

–马丁
19 Mar 26 '19 at 13:51

#25 楼

var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));


评论


此答案中需要更多的理由/说明。 AggregateObject添加到KeyValuePair中是什么?问题中所要求的“迭代”在哪里?

– Marc L.
17年12月29日在16:37

选择遍历字典并允许我们处理每个对象。它不像foreach那样通用,但是我已经使用了很多。我的回答是否值得投票?

– Egor Okhterov
18年6月2日在18:37

不,Select使用迭代来影响结果,但它本身不是迭代器。迭代(foreach)用于的事物类型(尤其是具有副作用的操作)不在Linq的范围内,包括Select。在实际枚举aggregateObjectCollection之前,lambda不会运行。如果将此答案视为“第一条路线”(即在直接进行foreach之前使用),则会鼓励不良做法。有时,Linq操作可能在迭代字典之前很有用,但是并不能解决所要求的问题。

– Marc L.
18年6月4日在16:11



#26 楼

我只想加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));
});


替代这会增加一个“ .ToList()”的调用,可能会稍微改善性能(如此处所指出的foreach与someList.Foreach(){}),尤其是在使用大型词典并在并行是没有选择的/根本不会起作用。

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

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

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );


评论


完全复制整个集合不会改善性能。它将极大地减慢代码的速度,并使几乎不占用额外内存的代码的内存占用量增加一倍。

–服务
16-09-16在16:08

我避免使用副作用“ List.ForEach”方法:foreach强制增加副作用可见性,即它所属的位置。

–user2864740
17-3-28在22:30



#27 楼

Dictionary 是c#中的通用集合类,它以键值格式存储数据。键必须是唯一的,并且不能为null,而值可以重复和为null。视为表示键及其值的KeyValuePair 结构。因此,我们应该在元素迭代期间采用元素类型KeyValuePair 。下面是示例。

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");

foreach (KeyValuePair<int, string> item in dict)
{
    Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}


#28 楼

如果要使用for循环,可以执行以下操作:

var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
   var key= keyList[i];
   var value = dictionary[key];
 }


评论


但是,这样做有什么好处?它比foreach循环更长的代码,并且性能更差,因为新的List (dictionary.Keys)会迭代字典。在您有机会自己对其进行迭代之前,需要计数一次。除了要求“最佳方式”是主观的,我不认为这将成为问题寻求的“最佳方式”还是“标准方式”。对于“如果要使用for循环...”,我将提出反对“不要使用for循环”。

–培根
5月15日17:58

如果您有大量集合,并且foreach的操作速度很慢,并且在迭代时集合可以更改,则可以保护您免受“集合已更改”错误的影响,并且此解决方案比使用ElementAt具有更好的性能。

–SeçkinDurgay
5月16日12:01



我同意避免“例外”的例外是这样做的原因之一,尽管问题中没有说明这种特殊情况,而且总是可以做foreach(dictionary.ToArray()中的var pair)。不过,我认为最好在答案中阐明一个人想要使用此代码的特定场景以及这样做的含义。

–培根
5月16日19:26

是的,您是对的,但是ElementAt这里有一个答案,它具有很高的声誉,我输入了这个答案:)

–SeçkinDurgay
5月16日20:12

#29 楼

只需使用linq

 Dictionary<int, string> dict = new Dictionary<int, string>();
 dict.Add(1, "American Ipa");
 dict.Add(2, "Weiss");
 dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );


评论


我看到您正在调用ToList(),因为ForEach()仅在List <>类上定义,但是为什么要做所有这些,而不仅仅是foreach(dict中的变量对){}?我会说这更简单,并且没有相同的内存/性能含义。无论如何,早在3.5年前就已经在此答案中提出了这种精确的解决方案。

–培根
4月30日下午2:20

仅出于代码可视化的目的,它确实可以按照您指定的方式完成,我只是想以其他方式展示它,并且在我的较瘦观点中,我很抱歉没有看到所示的答案,只是一个拥抱

–路易斯·费尔南多·科雷阿·莱特
5月1日12:42

#30 楼

除了排名最高的帖子之外,还讨论了使用

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}




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


因为您可以从初始化中看到字典类型,所以完成以下操作,kvp是KeyValuePair

var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x

foreach(var kvp in myDictionary)//iterate over dictionary
{
    // do something with kvp.Value or kvp.Key
}


评论


创建和复制第二个字典不是代码可读性的有效解决方案。实际上,我认为这会使代码更难理解,因为现在您必须问自己:“为什么最后一个家伙创建了第二本词典?”如果您想更详细些,只需使用选项一。

–马修·古拉特(Matthew Goulart)
18年9月6日在19:23

我只是想向您显示,当每个命令之前都进行了dict声明时,声明中就清楚了foreach中的用法

–BigChief
18年9月8日9:03