我有以下代码:
foreach (var bar in dataFromDataFeed.Where(bar => bar.Key < fromTicks
|| bar.Key > toTicks))
{
dataFromDataFeed.Remove(bar.Key);
}
这是安全还是我需要先将foreach
内的IEnumerable转换为Dictionary<T,U>
?
感谢。
答案 0 :(得分:5)
不,那会炸弹或者让你得到一个仍然有坏元素的结果。只需反转Where表达式:
var filtered = dataFromDataFeed.Where(bar => bar.Key >= fromTicks && bar.Key <= toTicks);
dataFromFeed = filtered.ToList(); // optional
目前还不清楚你是否确实需要更新列表,因为你有一个非常好的枚举器,所以通常没有必要,所以最后一个语句是// optional
。
请记住,像在原始代码中一样使用Remove()会有O(n * m)复杂度,非常不好。使用ToList()仅为O(m)但需要O(m)存储。记忆的交易速度是一个常见的程序员的决定,但这是一个灌篮,除非m是巨大的(数亿和你正在与OOM战斗)或非常小。考虑到表达式,两者都不应该适用。
答案 1 :(得分:1)
由于您正在迭代集合,因此会抛出错误。在对其进行枚举时,不支持修改集合。
使用 ToList()
foreach (var bar in dataFromDataFeed.Where(bar => bar.Key < fromTicks
|| bar.Key > toTicks).ToList())
{
dataFromDataFeed.Remove(bar.Key);
}
答案 2 :(得分:1)
在枚举时修改集合被认为是不好的做法,在很多情况下,这会导致抛出InvalidOperationException
。
您应该将值复制到另一个列表或数组中(例如,在ToList()
调用后调用Where()
),然后您将不会修改原始数据。
foreach (var bar in dataFromDataFeed.Where(bar => bar.Key < fromTicks || bar.Key > toTicks).ToList())
{
dataFromDataFeed.Remove(bar.Key);
}
答案 3 :(得分:1)
尽管Dictionary
几乎肯定会包含一个方法,该方法对每个项目都有谓词函数并删除该谓词返回true的所有项目,但它并不是。因此,如果一个Dictionary
包含一些与谓词匹配的项目而另一些项目不匹配,那么获取字典的唯一方法就是只包含不满足谓词的项目。构建满足谓词的所有项目的列表,然后从字典中删除列表中的所有项目,或者构建一个仅包含不满足谓词的项目的字典,并放弃原始项目以支持新的项目一。哪种方法更好将取决于要保留和丢弃的项目的相对数量。
作为替代方案,可以切换到使用ConcurrentDictionary
。与Dictionary
不同,ConcurrentDictionary
将允许移除项目而不会使正在进行的任何枚举失效。如果只删除枚举的项目,我希望ConcurrentDictionary
能够完全按照预期进行枚举。如果枚举一个项目有时会导致代码删除不同的项目,那么必须准备代码,以便删除尚未枚举的项目但不需要,导致该项目从枚举中省略。
虽然Dictionary
通常比ConcurrentDictionary
更快,但如果&#34;删除项目,则使用后者可能是值得的...&#34;操作很常见,必须删除或复制集合中的大部分项目。