修改“foreach”中的列表的最佳方法是什么? 环形?
C# / .NET 4.0 中的一项新功能是,您可以在 foreach
中更改枚举而不会出现异常。 请参阅 Paul Jackson 的博客文章 并发的有趣副作用:枚举时从集合中删除项目了解有关此更改的信息。
执行以下操作的最佳方法是什么?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
通常我使用 IList
作为缓存/缓冲区,直到 foreach
结束,但是有更好的方法吗?
A new feature in C# / .NET 4.0 is that you can change your enumerable in a foreach
without getting the exception. See Paul Jackson's blog entry An Interesting Side-Effect of Concurrency: Removing Items from a Collection While Enumerating for information on this change.
What is the best way to do the following?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
Usually I use an IList
as a cache/buffer until the end of the foreach
, but is there better way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
在本例中使用 IEnumerable 扩展方法创建枚举的副本,然后对其进行枚举。 这会将每个内部可枚举中的每个元素的副本添加到该枚举中。
Make a copy of the enumeration, using an IEnumerable extension method in this case, and enumerate over it. This would add a copy of every element in every inner enumerable to that enumeration.
为了说明 Nippysaurus 的答案:如果您要将新项目添加到列表中,并希望在同一枚举期间也处理新添加的项目,那么您只需使用 for循环而不是 foreach 循环,问题解决了:)
对于可运行的示例:
最后一个示例的输出:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5、7、9、
清单(15 项)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
To illustrate Nippysaurus's answer: If you are going to add the new items to the list and want to process the newly added items too during the same enumeration then you can just use for loop instead of foreach loop, problem solved :)
For runnable example:
Output of last example:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
List (15 items)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
如前所述,但有一个代码示例:
As mentioned, but with a code sample:
在这种情况下,您确实应该使用
for()
而不是foreach()
。You should really use
for()
instead offoreach()
in this case.您无法在枚举时更改可枚举集合,因此您必须在枚举之前或之后进行更改。
for
循环是一个不错的替代方案,但如果您的IEnumerable
集合未实现ICollection
,则这是不可能的。要么:
1) 首先复制集合。 枚举复制的集合并在枚举过程中更改原始集合。 (@tvanfosson)
或
2) 保留更改列表并在枚举后提交它们。
You can't change the enumerable collection while it is being enumerated, so you will have to make your changes before or after enumerating.
The
for
loop is a nice alternative, but if yourIEnumerable
collection does not implementICollection
, it is not possible.Either:
1) Copy collection first. Enumerate the copied collection and change the original collection during the enumeration. (@tvanfosson)
or
2) Keep a list of changes and commit them after the enumeration.
LINQ 对于处理集合非常有效。
我不清楚你的类型和结构,但我会尽我所能来适应你的例子。
从您的代码看来,对于每个项目,您都将其自己的“Enumerable”属性中的所有内容添加到该项目中。 这非常简单:
作为一个更一般的示例,假设我们要迭代一个集合并删除满足某个条件的项目。 避免
foreach
,使用 LINQ:根据每个现有项目添加一个项目? 没问题:
LINQ is very effective for juggling with collections.
Your types and structure are unclear to me, but I will try to fit your example to the best of my ability.
From your code it appears that, for each item, you are adding to that item everything from its own 'Enumerable' property. This is very simple:
As a more general example, let's say we want to iterate a collection and remove items where a certain condition is true. Avoiding
foreach
, using LINQ:Add an item based on each existing item? No problem:
以下是您可以做到这一点的方法(快速而肮脏的解决方案。如果您确实需要这种行为,您应该重新考虑您的设计或覆盖所有
IList
成员和聚合源列表):Here's how you can do that (quick and dirty solution. If you really need this kind of behavior, you should either reconsider your design or override all
IList<T>
members and aggregate the source list):要添加 Timo 的答案,LINQ 也可以这样使用:
To add to Timo's answer LINQ can be used like this as well:
从性能角度来看,最好的方法可能是使用一两个阵列。 将列表复制到数组,对数组进行操作,然后从数组构建一个新列表。 访问数组元素比访问列表项更快,并且
List
和T[]
之间的转换可以使用快速“批量复制”操作,从而避免访问单个项目的相关开销。例如,假设您有一个
List
并希望列表中以T
开头的每个字符串后跟一个项目“Boo”,而每个字符串以“U”开头的内容被完全删除。 最佳方法可能是这样的:如果
List
提供一种从数组的一部分构造列表的方法,那将会很有帮助,但我不知道有任何有效的方法这样做。 尽管如此,数组上的操作还是相当快的。 值得注意的是,从列表中添加和删除项目不需要“推动”其他项目; 每个项目都直接写入数组中的适当位置。The best approach from a performance perspective is probably to use a one or two arrays. Copy the list to an array, do operations on the array, and then build a new list from the array. Accessing an array element is faster than accessing a list item, and conversions between a
List<T>
and aT[]
can use a fast "bulk copy" operation which avoids the overhead associated accessing individual items.For example, suppose you have a
List<string>
and wish to have every string in the list which starts withT
be followed by an item "Boo", while every string that starts with "U" is dropped entirely. An optimal approach would probably be something like:It would have been helpful if
List<T>
provided a method to construct a list from a portion of an array, but I'm unaware of any efficient method for doing so. Still, operations on arrays are pretty fast. Of note is the fact that adding and removing items from the list does not require "pushing" around other items; each item gets written directly to its appropriate spot in the array.我编写了一个简单的步骤,但由于这一步骤,性能会下降,
这是我的代码片段:-
I have written one easy step, but because of this performance will be degraded
Here is my code snippet:-
foreach 中使用的集合是不可变的。 这很大程度上是设计使然。
正如 MSDN 上所述:
链接 表明新的并发集合中允许这样做。
The collection used in foreach is immutable. This is very much by design.
As it says on MSDN:
The post in the link provided by Poko indicates that this is allowed in the new concurrent collections.