You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何过滤Dictionary<int, List<int>>类型字典中的列表值?

如何安全过滤字典中值列表的元素且不破坏迭代器

你的代码里主要有两个问题:一是Where方法不会原地修改原列表,只是返回一个延迟执行的枚举序列;二是直接在遍历字典键值对时的局部变量赋值根本没生效,而且如果后续不小心修改字典键集合还会触发迭代器异常。下面给你几种靠谱的解决方案:

方案1:创建新字典(最安全简洁)

如果你不需要保留原字典的内容,直接生成一个过滤后的新字典是最省心的方式,完全规避迭代器相关的问题:

Dictionary<int, List<int>> foo = GetFoo();
var filteredFoo = foo.ToDictionary(
    kvp => kvp.Key,
    kvp => kvp.Value.Where(item => item % 2 == 0).ToList()
);

这里用ToList()把Where返回的延迟序列固化成List,避免后续重复执行过滤逻辑,也完美匹配字典值的类型要求。

方案2:遍历键的副本修改原字典

如果你必须修改原字典,建议先把字典的键转换成数组(生成一个快照),再遍历这个数组修改对应的值:

Dictionary<int, List<int>> foo = GetFoo();
// 生成键的副本,避免遍历过程中字典结构变化影响迭代
foreach (var key in foo.Keys.ToArray())
{
    var filteredItems = foo[key].Where(item => item % 2 == 0).ToList();
    foo[key] = filteredItems;
}

这样即使遍历过程中字典的键集合发生变化(比如添加/删除键),也不会影响当前的迭代,因为我们遍历的是独立的键数组。

方案3:原地修改原列表(减少内存分配)

如果你想直接在原列表上修改而不替换整个列表引用,可以反向遍历列表并移除不符合条件的元素:

Dictionary<int, List<int>> foo = GetFoo();
foreach (var (key, items) in foo)
{
    // 反向遍历避免移除元素后索引错乱
    for (int i = items.Count - 1; i >= 0; i--)
    {
        if (items[i] % 2 != 0)
        {
            items.RemoveAt(i);
        }
    }
}

这种方式不需要创建新的List,直接修改原列表内容,而且遍历字典键值对时修改值的内容是安全的——只要不改变字典的键集合,就不会触发迭代器异常。

原代码问题解析

  1. 局部变量赋值无效:items = items.Where(...)只是改变了foreach循环里局部变量items的引用,字典里的原列表根本没变化,必须显式把过滤后的结果赋值回foo[key]才会生效。
  2. 延迟执行的隐患:Where返回的是IEnumerable<int>,如果不转成List,每次访问这个值都会重新执行过滤逻辑,既影响性能,还可能因为原列表后续修改导致结果变化。
  3. 迭代器风险:虽然单纯修改字典的值不会触发迭代器异常,但如果后续代码不小心在遍历过程中添加/删除键,就会抛出InvalidOperationException,用键的副本或者新字典可以彻底避免这个问题。

内容的提问来源于stack exchange,提问作者user3310334

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 00:34:07