我正在尝试修改for value中的列表
for (int i = 0; i < theList.Count; i++) {
if(someCircunstances)
theList.remove(component);
else
theList.add(component);
}
我使用此方法获得ArgumentOutOfRangeException
。
有没有办法来实现这个目标?
答案 0 :(得分:2)
在迭代列表时改变列表也是一种不好的做法。
这是另一种选择:
theList.RemoveAll(someCircunstances);
答案 1 :(得分:2)
可以通过向后迭代并使用索引而不是项来解决:
for (int i = list.Count - 1; i > 0; i--)
{
if(condition)
list.RemoveAt(i);
else
list.Add(component);
}
一些解释:当您对集合进行迭代时,不应更改范围中的项目。迭代器将检测到并抛出(如果是foreach
,则必须使用列表副本)。但是在使用索引(RemoveAt()
方法)和向后迭代的情况下,您可以安全地进行下一次迭代,但范围不包括已删除的项目。 Add()
正在添加到最后,因此新项目永远不会在范围内。
我将添加更多解决方案,其中一个更好地决定自己:
经典 foreach,先复制:
foreach(var item in list.ToArray()) // imho `ToArray` is better than `ToList`
if(condition)
list.Remove(item);
else
list.Add(component);
结果新列表:
var result = new List<...>();
foreach(var item in list)
result.Add(condition ? component : item); // not sure here, but should give you idea
list = result;
答案 2 :(得分:0)
您将超出范围异常,因为索引从0开始。
如上所述,一种解决方案是从List.count中删除1,另一种解决方案是在1而不是0时启动i。
想一想:如果你的列表中有1个元素,那个元素的索引是0,如果你有100个元素,你的hundreth元素的索引是99。
你正在考虑如下列表:[1] [2] [3],而它实际上是[0] [1] [2]
答案 3 :(得分:0)
这里的问题是你要删除列表中的值,然后使用已经删除的索引再次迭代它 - &gt; ArgumentOutOfRangeException
所以要解决这个问题,我建议你把它分成两个for循环:
for (int i = theList.Count - 1; i >= 0; i--) {
if(someCircunstances)
theList.remove(component);
}
for (int i = 0; i < theList.Count; i++) {
if(someCircunstances)
theList.add(component);
}
答案 4 :(得分:0)
我同意Tamas,在迭代时不要改变列表,还有另一种方法来实现你的观点
List<someType> ToRemove=new List<someType>() ; //some type is same type as theList is
List<someType> ToAdd=new List<someType>();
for (int i = 0; i < theList.Count; i++) {
if(someCircunstances)
ToRemove.add(component);
else
ToAdd.add(component);
}
theList=((theList.Except(ToRemove)).Concat(ToAdd)).ToList();
答案 5 :(得分:0)
根据评论,您需要能够为新创建的项目应用相同的逻辑。
你需要做这样的事情:
public void DoIt(List<MyObject> theList)
{
List<MyObject> items_to_remove = new List<MyObject>();
List<MyObject> items_to_add = new List<MyObject>();
for (int i = 0; i < theList.Count; i++)
{
if (someCircunstances)
items_to_remove.Add(....); //Remove some existing item
else
items_to_add.Add(....); //Add a new item
}
if(items_to_remove.Count > 0)
items_to_remove.ForEach(x => theList.Remove(x));
if (items_to_add.Count > 0)
{
DoIt(items_to_add); //Recursively process new objects
theList.AddRange(items_to_add);
}
}
您的想法是在自己的列表中插入要添加的项目和要删除的项目。
然后在迭代后,删除需要删除的项目。
之后,您需要添加要添加的项目。但是,在这之前你需要对它们运行相同的逻辑,这就是递归调用的解释。
请注意我使用的是MyObject
,因为我不知道您的列表类型。使用您正在使用的任何类型。
答案 6 :(得分:0)
如果你可以使用循环的当前索引从lst中删除项目,你可以这样轻松地执行此操作:
using System;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var numbers = Enumerable.Range(1, 20).ToList();
var rng = new Random();
for (int i = 0; i < numbers.Count; ++i)
{
if (rng.NextDouble() >= 0.5) // If "someCircumstances"
{
numbers.Add(numbers[i]*2);
}
else
{
// Assume here you have some way to determine the
// index of the item to remove.
// For demo purposes, I'll just calculate a random index.
int index = rng.Next(0, numbers.Count);
if (index >= i)
--i;
numbers.RemoveAt(index);
}
}
Console.WriteLine(string.Join("\n", numbers));
}
}
}
这也会循环添加到列表末尾的所有数字。 numbers.Count
的值在每次迭代时重新计算,因此当它更改时,循环将适当地扩展。
(Offtopic)奖金问题:在上面的代码中,当循环退出时,列表的平均大小是多少?什么是最大尺寸?