删除给定索引处的列表元素

mih*_*hai 10 c# list

我有一个列表,其中包含一些字符串类型的项目.

List<string> lstOriginal;
Run Code Online (Sandbox Code Playgroud)

我有另一个列表,其中包含应从第一个列表中删除的id.

List<int> lstIndices;
Run Code Online (Sandbox Code Playgroud)

我试图用RemoveAt()方法完成这项工作,

foreach(int indice in lstIndices)
{
     lstOriginal.RemoveAt(indice);
}
Run Code Online (Sandbox Code Playgroud)

但它崩溃并且说我"索引超出范围".

das*_*ght 31

您需要对要从最大到最小返回的索引进行排序,以避免在错误的索引处删除某些内容.

foreach(int indice in lstIndices.OrderByDescending(v => v))
{
     lstOriginal.RemoveAt(indice);
}
Run Code Online (Sandbox Code Playgroud)

这是为什么:让我们说有五个项目的清单,并且希望在索引中删除项目24.如果首先删除该项2,则索引处的项目4将位于索引处3,索引4将不再位于列表中(导致您的异常).如果你倒退,所有索引都会在你准备删除相应项目的那一刻.

  • @YoryeNathan假设列表中的索引已经按升序排列.如果它们是无序的,你需要做某种类型的排序. (5认同)

pho*_*oog 6

你如何填写指数列表?RemoveAll您可以使用更有效的方法.例如,而不是这样:

var indices = new List<int>();
int index = 0;
foreach (var item in data)
    if (SomeFunction(data))
        indices.Add(index++);

//then some logic to remove the items
Run Code Online (Sandbox Code Playgroud)

你可以这样做:

data.RemoveAll(item => SomeFunction(item));
Run Code Online (Sandbox Code Playgroud)

这最大限度地减少了将项目复制到阵列中的新位置; 每个项目只复制一次.

您还可以在上面的示例中使用方法组转换,而不是lambda:

data.RemoveAll(SomeFunction);
Run Code Online (Sandbox Code Playgroud)


Oma*_*aha 5

之所以发生这种情况,是因为当你从列表中删除一个项目时,每个项目的索引会有效地减少一个,所以如果你按照增加的索引顺序删除它们,并且原始列表末尾附近的某些项目是删除后,这些索引现在无效,因为删除前面的项目后列表会变短.

最简单的解决方案是按递减顺序对索引列表进行排序(最高索引优先),然后对其进行迭代.


Sim*_*Var 5

for (int i = 0; i < indices.Count; i++)
{
    items.RemoveAt(indices[i] - i);
}
Run Code Online (Sandbox Code Playgroud)

  • @meorfi写了我之前的评论,我记得`RemoveAll`方法,它进一步降低了复制开销.然而,问题不清楚是否可以在这里应用. (2认同)