ChatGPT解决这个技术问题 Extra ChatGPT

如何遍历字典?

我已经看到了几种在 C# 中迭代字典的不同方法。有标准方法吗?

@VikasGupta 当您不知道键将是什么时,您会建议使用键值对集合做什么?
@displayName 如果你想对每个键值对做一些事情,但没有对用于查找值的键的引用,你会遍历字典,对吗?我只是指出,有时你会想要这样做,尽管 Vikas 声称这通常是不正确的用法。
说这是不正确的用法意味着有更好的选择。那是什么选择?
VikasGupta 是错误的,我可以肯定,经过多年在非理论场景中的高性能 C# 和 C++ 编程。确实经常会创建一个字典,存储唯一的键值对,然后迭代这些值,这些值被证明在集合中具有唯一的键。创建任何进一步的集合是避免字典迭代的一种非常低效且昂贵的方法。请提供一个很好的替代方案来回答澄清您的观点的问题,否则您的评论非常荒谬。
VikasGupta 是 100% 正确的。如果您有“键值对集合”并且不知道如何处理它,您可以字面上将它放入 ICollection<KeyValuePair>(最简单的实现: List)。如果您关心“高性能编程”,那么您应该知道字典唯一更快的是通过键查找项目 - 添加项目较慢且iterating over a dictionary can easily take twice as long as iterating over a list

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

这很好,但是是否有任何简洁的语法可以将键和值从 KeyValuePair 解压缩到它们自己的变量中?例如,在 Python 中,如果我知道我的键是人名和值地址,我可能会写 for (name, address) in myDictionary.items()
@user2428107 您可以在 c# 中使用解构来完成此操作。 foreach (var (key, value) in myDictionary)
J
Jacob

如果您尝试在 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 应该谨慎使用。特别是在这里,它不是建设性的:类型 KeyValuePair 可能与问题相关。
var 有一个独特的目的,我不认为它是“句法”糖。有目的地使用它是一种适当的方法。
在 foreach 语句中使用 var 是危险的,因为有时编译器将“var”替换为“object”而不是使用正确的类型。
@JamesWierzba 我会说影响可读性的是缺少一个好的变量名(因为它是一个演示示例)。在实际代码中,如果它是 foreach (var vehicle in line.Values) { start(vehicle); },它将是可读的。
K
Kolappan N

在某些情况下,您可能需要一个可能由 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 中。自动生成的测试类。
如果您要修改与键关联的值,这是要走的路。否则在修改和使用 foreach() 时会抛出异常。
ElementAt 不是 O(n) 操作吗?
这个答案完全不值得这么多赞成。字典没有隐式顺序,因此在此上下文中使用 .ElementAt 可能会导致细微的错误。更严重的是上面阿图罗的观点。您将迭代字典 dictionary.Count + 1 次,导致 O(n^2) 复杂度的操作应该仅为 O(n)。如果您确实需要索引(如果需要,您可能首先使用了错误的集合类型),您应该迭代 dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value}) 而不是在循环内使用 .ElementAt
ElementAt - o(n) 操作!严重地?这是你不应该怎么做的例子。这么多赞?
J
J Healy

取决于您是追求键还是值...

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

M
Mark Cooper

一般来说,在没有特定上下文的情况下询问“最好的方式”就像问什么是最好的颜色?

一方面,有很多颜色,没有最好的颜色。这取决于需要,通常也取决于口味。

另一方面,有很多方法可以在 C# 中迭代字典,并且没有最好的方法。这取决于需要,通常也取决于口味。

最直接的方法

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 你确定吗? OrderBy 返回的值不是 KeyValuePair 类型,它们没有 Value 字段。我在这里看到的确切类型是 IOrderedEnumerable<KeyValuePair<TKey, TValue>>。也许你的意思是别的?你能写一个完整的行来说明你的意思(并测试它)吗?
我认为这个答案包含我的意思:stackoverflow.com/a/141105/5962841 但如果我混淆了某些东西,请纠正我
@Mafii 重新阅读我的整个答案,代码部分之间的解释说明了上下文。您提到的答案就像我的答案中的第二个代码部分(不需要顺序)。我刚刚按照您的建议写了items.Value。在您评论的第四部分的情况下,Select() 是一种使 foreach 直接枚举字典中的值而不是键值对的方法。如果在这种情况下您不喜欢 Select(),您可能更喜欢第三个代码部分。第四部分的重点是表明可以使用 LINQ 对集合进行预处理。
如果您执行 .Keys.Orderby(),您将迭代一个键列表。如果这就是你所需要的,那很好。如果您需要值,那么在循环中,您必须在每个键上查询字典以获取值。在许多情况下,它不会产生实际的影响。在高性能场景中,它会。就像我在答案开头所写的那样:“有很多方法(......)并且没有最好的方法。这取决于需要,而且通常也取决于品味。”
J
Jaider

C# 7.0 introduced 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}");
}

https://i.stack.imgur.com/OdW3m.png


如果您使用的 .NET Framework,至少 4.7.2 没有 KeyValuePair 上的解构,试试这个:foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
p
phoenix

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

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

那是你要找的吗?


O
Onur

您也可以在用于多线程处理的大字典上尝试此操作。

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

@WiiMaxx 更重要的是,如果这些项目不相互依赖
M
M Reza

我很欣赏这个问题已经有很多回应,但我想进行一些研究。

与迭代数组之类的东西相比,迭代字典可能会相当慢。在我的测试中,对数组的迭代需要 0.015003 秒,而对字典(具有相同数量的元素)的迭代需要 0.0365073 秒,是 2.4 倍!虽然我看到了更大的差异。为了比较,列表介于 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);
}

在这里,正常的 foreach 运行耗时 0.2820564 秒(大约是单次迭代耗时的十倍——如您所料)。对键的迭代花费了 2.2249449 秒。

编辑添加:阅读其他一些答案让我质疑如果我使用 Dictionary 而不是 Dictionary 会发生什么。在这个例子中,数组耗时 0.0120024 秒,列表耗时 0.0185037 秒,字典耗时 0.0465093 秒。可以合理地预期数据类型会影响字典的速度。

我的结论是什么?

如果可以,请避免迭代字典,它们比迭代具有相同数据的数组要慢得多。

如果您确实选择遍历字典,请不要太聪明,尽管速度较慢,但您可能会比使用标准 foreach 方法做得更糟。


您应该使用 StopWatch 而不是 DateTime 之类的东西进行测量:hanselman.com/blog/…
你能否描述一下你的测试场景,你的字典中有多少项目,你多久运行一次你的场景来计算平均时间,......
有趣的是,根据字典中的数据,您会得到不同的结果。在迭代字典时,枚举器函数必须跳过字典中的许多空槽,这导致它比迭代数组慢。如果 Dictionary 已满,则要跳过的空槽将比它为半空时少。
r
rucamzu

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

有了这个,就可以以与 KeyValuePair 无关的方式遍历字典:

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

// ...

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

f
frostbyte

有很多选择。我个人最喜欢的是 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 如果没有人知道 var 是什么,那么您的命名不正确
P
Pavel

使用 .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 包使用。更重要的是,Deconstruct 方法需要 C# 7.0+ 才能作为 var (fruit, number) in fruits 的解构器。
F
Franziee

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

即使没有 Deconstruct 扩展方法,for 循环也可以工作
P
Pixel_95

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

https://i.stack.imgur.com/Nr35i.png


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

迭代字典的最简单形式:

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

s
sɐunıɔןɐqɐp

使用 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'
}


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

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

与直接使用 KeyValuePair 相比,调用用于创建 tuple 的扩展方法的开销很小,如果您分配 KeyValuePair 的属性 KeyValue,这应该不是问题无论如何都要到新的循环变量。

在实践中,这种新语法非常适合大多数情况,除了低级超高性能场景,您仍然可以选择在特定位置不使用它。

看看这个:MSDN Blog - New features in C# 7


喜欢“舒适”元组而不是键值对的原因是什么?我在这里看不到收益。您的元组包含一个键和一个值,键值对也是如此。
嗨 Maarten,谢谢你的提问。主要好处是代码可读性,无需额外的编程工作。对于 KeyValuePair,必须始终使用 kvp.Keykvp.Value 的形式分别使用键和值。使用元组,您可以根据需要灵活地命名键和值,而无需在 foreach 块内使用进一步的变量声明。例如,您可以将键命名为 factoryName,将值命名为 models,这在您获得嵌套循环(字典的字典)时特别有用:代码维护变得更加容易。试一试吧! ;-)
佚名

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

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

这是我唯一能够在从 DictionaryBase 继承的类中正常运行的功能。


这看起来像使用字典的非泛型版本时......即在 .NET 框架 2.0 之前。
@joed0tnot:它是用于 Hashtable 对象的非泛型版本
e
ender

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

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 结构中。
仅供参考,该链接中的最后一个测试是测试错误的东西:它测量迭代键,忽略值,而前两个测试确实使用该值。
b
boca

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

    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););

S
Seçkin Durgay

如果你想使用 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 循环长并且性能更差,因为 new List<string>(dictionary.Keys) 将在您有机会自己迭代之前迭代 dictionary.Count 次。撇开要求“最佳方式”是主观的不谈,我不认为这将如何成为问题所寻求的“最佳方式”或“标准方式”。对于“如果你想使用 for 循环......”我会用“不要使用 for 循环”来反驳。
如果您有大量集合并且 foreach 中的操作很慢,并且如果您的集合在迭代时可以更改,它可以保护您免受“集合已更改”错误的影响,并且此解决方案具有比使用 ElementAt 更好的性能。
我同意避免“集合已修改”例外是这样做的一个原因,尽管问题中没有说明这种特殊情况并且总是可以做foreach (var pair in dictionary.ToArray()) { }。不过,我认为最好在答案中明确说明希望使用此代码的具体场景以及这样做的影响。
是的,你是对的,但是 ElementAt 有一个答案,它有很高的声誉,我输入了这个答案:)
y
yazanpro

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

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

N
Nick

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

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

S
Steven Delrue

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

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 (...) { }... 似乎没有必要。
佚名

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

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

S
Sheo Dayal Singh

Dictionary< TKey, TValue > 是c#中的一个通用集合类,它以键值格式存储数据。key必须唯一且不能为null,而value可以重复且为null。因为字典中的每一项都是视为 KeyValuePair< TKey, TValue > 结构,表示一个键及其值。因此我们应该在 element 的迭代过程中采用元素类型 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);
}

P
Philm

最好的答案当然是:想想,如果你打算迭代它,你是否可以使用比字典更合适的数据结构——正如 Vikas Gupta 在问题下的讨论(开始)中已经提到的那样。但是,作为整个线程的讨论仍然缺乏令人惊讶的好选择。一种是:

SortedList<string, string> x = new SortedList<string, string>();

x.Add("key1", "value1");
x.Add("key2", "value2");
x["key3"] = "value3";
foreach( KeyValuePair<string, string> kvPair in x )
            Console.WriteLine($"{kvPair.Key}, {kvPair.Value}");

为什么可以争论迭代字典的代码味道(例如通过 foreach(KeyValuePair<,>) ?

清洁编码的一个基本原则:“表达意图!” Robert C. Martin 在“干净的代码”中写道:“选择能够揭示意图的名称”。显然,仅命名太弱了。 “在每个编码决策中表达(揭示)意图”更好地表达了它。

一个相关的原则是“Principle of least surprise”(=Principle of Least Astonishment)。

为什么这与迭代字典有关?选择字典表达了选择主要用于按键查找数据的数据结构的意图。如今,.NET 中有很多替代方案,如果您想遍历键/值对,您可以选择其他东西。

此外:如果您对某些内容进行迭代,则必须揭示有关(将要)如何订购和预期如何订购这些项目的信息!尽管 Dictionary 的已知实现按照添加的项目的顺序对键集合进行排序 - AFAIK,但 Dictionary 没有关于排序的保证规范(有吗?)。

但是有什么替代方案?

TLDR:SortedList:如果您的集合没有变得太大,一个简单的解决方案是使用 SortedList<,>,它还可以为您提供键/值对的完整索引。

微软有一篇关于提及和解释合身系列的长文:
Keyed collection

提一下最重要的: KeyedCollection<,> 和 SortedDictionary<,> 。 SortedDictionary<,> 比 SortedList 快一点,仅当它变大时才插入,但缺少索引,并且只有在 O(log n) 插入优先于其他操作时才需要。如果您确实需要 O(1) 来插入并接受较慢的迭代作为交换,您必须使用简单的 Dictionary<,>。显然,对于所有可能的操作,没有最快的数据结构。

此外还有 ImmutableSortedDictionary<,>。

如果一个数据结构不是您所需要的,那么从 Dictionary<,> 甚至新的 ConcurrentDictionary<,> 派生并添加显式迭代/排序函数!


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

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

这个答案需要更多的理由/描述。 AggregateObjectKeyValuePair 添加了什么?问题中要求的“迭代”在哪里?
Select 遍历字典并允许我们处理每个对象。它不像 foreach 那样通用,但我用过很多次。我的回答真的值得反对吗?
不,Select 使用 迭代来影响结果,但它本身不是迭代器。迭代 (foreach) 用于的事物类型(尤其是具有副作用的操作)超出了 Linq 的范围,包括 Select。在实际枚举 aggregateObjectCollection 之前,lambda 不会运行。如果将此答案视为“第一条路径”(即,在直接 foreach 之前使用),则会鼓励不良做法。在某种情况下,迭代字典之前可能会有 Linq 操作有用,但这并不能解决所问的问题。
C
Community

只是想加我的 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 vs someList.Foreach(){} 所指出的),尤其是在使用大型字典并且并行运行时没有选择/不会有完全有效果。

另外,请注意,您将无法为 foreach 循环内的“值”属性分配值。另一方面,您也可以操纵“密钥”,可能会在运行时给您带来麻烦。

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

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

无缘无故复制整个集合不会提高性能。它会显着减慢代码速度,并将几乎不消耗额外内存的代码的内存占用增加一倍。
我避免使用副作用 'List.ForEach' 方法:foreach 强制提高副作用的可见性,它所属的位置。
不幸的是,您链接到一个问题而不是一个具体的答案。这个问题有 14 个答案,其中一些很长。您能否链接到支持您的陈述的确切答案,即 .ForEach() 可以提高 foreach 的性能?更好的是,还要引用或描述答案的相关部分,因为即使是 Stack Overflow 链接也可能会损坏(即已删除的答案)。
B
BigChief

除了在使用之间进行讨论的排名最高的帖子之外

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
}

创建和复制第二个字典不是代码可读性的有效解决方案。事实上,我认为这会使代码更难理解,因为现在你必须问自己:“为什么最后一个人要创建第二个字典?”如果您想更详细,只需使用选项一。
我只是想告诉你,当 decl dict 之前为 each 时,foreach 中的用法从声明中很清楚