C#中的字典枚举

34

如何枚举字典?

假设我使用foreach()进行字典枚举。然而,在foreach()中无法更新键值对。因此,我需要其他方法。

4个回答

93
要枚举一个字典,你可以枚举其中的值:
Dictionary<int, string> dic;

foreach(string s in dic.Values)
{
   Console.WriteLine(s);
}

或者是KeyValuePairs

foreach(KeyValuePair<int, string> kvp in dic)
{
   Console.WriteLine("Key : " + kvp.Key.ToString() + ", Value : " + kvp.Value);
}
或者键值
foreach(int key in dic.Keys)
{
    Console.WriteLine(key.ToString());
}
如果您希望更新字典中的项,需要稍微不同地这样做,因为您无法在枚举实例时更新该实例。您需要枚举另一个不被更新的集合,就像这样:
Dictionary<int, string> newValues = new Dictionary<int, string>() { 1, "Test" };
foreach(KeyValuePair<int, string> kvp in newValues)
{
   dic[kvp.Key] = kvp.Value; // will automatically add the item if it's not there
}

要删除项目,可以按照类似的方式进行操作,枚举要删除的项目的集合,而不是字典本身。

List<int> keys = new List<int>() { 1, 3 };
foreach(int key in keys)
{
   dic.Remove(key);
}

或者您可以枚举键。 - strager
3
根据我的经验,列举字典中的键比仅列举值更常见,因为您可以很容易地找到键对应的值(这也是使用字典的原因)。请注意,此处的翻译并非解释,并尽量保持忠实于原文意思。 - Wedge
1
这里涵盖了枚举,但不包括更新。要进行更新,您需要使用以下方法之一...请参见spender的答案。 - Edyn

9

针对问题“I can't update value/key inside foreach()”,在枚举集合时不能修改它。我会通过创建Keys集合的副本来解决这个问题:

Dictionary<int,int> dic=new Dictionary<int, int>();

//...fill the dictionary

int[] keys = dic.Keys.ToArray();
foreach (int i in keys)
{
    dic.Remove(i);
}

不需要使用.ToArray(),据我所知。.Keys 返回一个 IEnumerable。 - strager
2
当然可以,但如果在循环中更改了字典,那么该枚举会发生什么变化呢?它肯定会改变。 - spender
我本来不会这么想的。在这种情况下,dic.Keys将返回一个IEnumerable<int>,其中包含所有值。如果您只使用IEnumerator<int>,那么可能会出现这种情况。 - Ian
5
将代码中的行: foreach(int i in keys) 修改为 foreach(int i in dic.keys) 会抛出 InvalidOperationException 异常,提示“集合已被修改;枚举操作无法执行。” 像上面那样创建一个副本则不会出现这种错误。 - spender
1
你仍然可以在行内完成它,只需添加.ToArray()...所以foreach(int i in dic.Keys.ToArray()) - Edyn
1
当然,你可以在行内完成它,但归根结底它还是一样的。在优化的发布二进制文件中,它可能会被内联。而在单独的行上,如果出现问题,更容易进行调试。 - spender

8

Foreach。有三种方法:您可以枚举 Keys 属性,也可以枚举 Values 属性,或者枚举字典本身,该字典是 KeyValuePair<TKey, TValue> 的枚举器。


2

我刚刚为列表回答了同样的(更新后的)问题,所以这里也是关于字典的同样内容。

public static void MutateEach(this IDictionary<TKey, TValue> dict, Func<TKey, TValue, KeyValuePair<TKey, TValue>> mutator)
{
    var removals = new List<TKey>();
    var additions = new List<KeyValuePair<TKey, TValue>>();

    foreach (var pair in dict)
    {
        var newPair = mutator(pair.Key, pair.Value);
        if ((newPair.Key != pair.Key) || (newPair.Value != pair.Value))
        {
            removals.Add(pair.Key);
            additions.Add(newPair);
        }
    }

    foreach (var removal in removals)
        dict.Remove(removal);

    foreach (var addition in additions)
        dict.Add(addition.Key, addition.Value);
}

请注意,我们必须在循环外进行更新,以便在枚举字典时不修改它。此外,这可以检测到由于使两个键相同而导致的冲突 - 这将抛出异常(由于使用了 Add)。例如 - 将所有键转换为小写并修剪所有值,使用 Dictionary<string, string>
myDict.MutateEach(key => key.ToLower(), value => value.Trim());

如果将键名转换为小写后不唯一,会抛出异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接