循环浏览列表和删除项目的正确方法
本文关键字:方法 删除项目 浏览 列表 循环 | 更新日期: 2023-09-27 18:32:11
我写了一个函数来遍历列表,并在满足某些条件时删除列表项。我的程序崩溃了,过了一会儿,我得出结论,外部的for循环遍历了列表中的所有项目。在同一个例程中,项目列表可能会变短。
// Lijst is a list of a struct that contains a value .scanned and .price
for (int i = 0; i < Lijst.Count; i++)
{
if (Lijst[i].scanned == false)
{
// (removed deletion of list item i here)
if (Lijst[i].price > (int)nudMinimum.Value)
{
Totaal++;
lblDebug.Text = Totaal.ToString();
}
Lijst.RemoveAt(i); //<-moved to here
}
}
现在我想知道这样做的正确方法是什么,而不会使索引超出范围错误。
为什么不直接List<T>.RemoveAll()
?
https://msdn.microsoft.com/en-us/library/wdka673a(v=vs.110).aspx
在您的情况下
Lijst.RemoveAll(item => some condition);
例如
// Count all the not scanned items each of them exceeds nudMinimum.Value
lblDebug.Text = Lijst
.Where(item => !item.scanned && item.price > (int)nudMinimum.Value)
.Count()
.ToString();
// Remove all not scanned items
Lijst.RemoveAll(item => !item.scanned);
你可能正在寻找这个
for (int i = Lijst.Count - 1 ; i >= 0 ; i--)
{
if (Lijst[i].scanned == false)
{
if (Lijst[i].price > (int)nudMinimum.Value)
{
Totaal++;
lblDebug.Text = Totaal.ToString();
}
Lijst.RemoveAt(i);
}
}
评论中的问题:
为什么循环的另一个方向会起作用?
因为当循环从零运行到计数时,会出现索引不可用且计数仍然存在的情况。例如:
如果列表中有 10 个项目,则循环从 0 开始并删除 0,1,2,3,4,现在剩下的项目是 5,索引也是 5,它也将删除该项目。之后,当循环值达到 6 并且剩余的项目为 4 时。然后它会产生一个问题。它会抛出错误。即索引超出范围
你去
// 1. Count items
lblDebug.Text = Lijst.Count(x => x.price > (int)nudMinimum.Value && !x.scanned).ToString();
//2. Remove items
Lijst.RemoveAll(x => !x.scanned);
问题是,当你删除元素编号 5 时,列表会变短,元素编号 6 现在是第 5 个,数字 7 变成了第 6 个,依此类推。但是,如果向后运行循环,则数字将按预期保留。
for(int i = donkeys.Count - 1; i >= 0; i++)
if(donkeys[i] == some condition here)
donkeys.RemoveAt(i);
然而,这是一种像老板一样的方法。有更好的方法。您已经有了答案,但我想建议一种基于 LINQ 的方法。
int Totaal = Lijst
.Where(item => item.scanned)
.Where(item => item.price > (int)nudMinimum.Value)
.Count();
Lijst = Lijst.Where(item => !item.scanned).ToList()
另外,作为旁注,我想知道您是否发现以下内容更具可读性。请考虑以下不同的命名(关于语言和大小写)。
List<Item> items = ...;
int minimum = (int)nudMinimum.Value;
int total = items
.Where(item => item.scanned)
.Where(item => item.price > minimum)
.Count();
items = items
.Where(item => !item.scanned)
.ToList();
首先,您要删除索引为 i 的元素,然后使用它。您需要首先使用具有索引 i 的元素执行您的过程,然后将其删除。您的代码将如下所示:
for (int i = 0; i < Lijst.Count; i++)
{
if (Lijst[i].scanned == false)
{
if (Lijst[i].price > (int)nudMinimum.Value)
{
Totaal++;
lblDebug.Text = Totaal.ToString();
}
Lijst.RemoveAt(i);
}
}
通常,如果要从列表中删除与谓词匹配的所有项目,请使用 List<T>.RemoveAll()
,例如:
List<int> test = Enumerable.Range(0, 10).ToList();
test.RemoveAll(value => value%2 == 0); // Remove all even numbers.
Console.WriteLine(string.Join(", ", test));
但是,您似乎需要进行一些额外的处理。您有两种选择:
- 分两步完成;首先使用
RemoveAll()
删除不需要的项目,然后循环访问列表以单独处理剩余项目。 - 改为从
List.Count-1
向后循环到0
。
你的代码有些格式不正确。首先,您删除了列表项,然后尝试获取该已删除项的价格。怎么可能。
所以你可以这样写。
for (int i = 0; i < Lijst.Count; i++)
{
if (Lijst[i].scanned == false)
{
if (Lijst[i].price > (int)nudMinimum.Value)
{
Totaal++;
lblDebug.Text = Totaal.ToString();
}
Lijst.RemoveAt(i);
}
}
List<string> list = new List<string>();
list.Add("sasa");
list.Add("sames");
list.Add("samu");
list.Add("james");
for (int i = list.Count - 1; i >= 0; i--)
{
list.RemoveAt(i);
}
如何从列表中删除项目