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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9908564/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 11:10:29  来源:igfitidea点击:

Remove list elements at given indices

c#list

提问by mihai

I have a list which contains some items of type string.

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

List<string> lstOriginal;

I have another list which contains idices which should be removed from first list.

我有另一个列表,其中包含应该从第一个列表中删除的 idice。

List<int> lstIndices;

I'd tried to do the job with RemoveAt()method ,

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

foreach(int indice in lstIndices)
{
     lstOriginal.RemoveAt(indice);
}

but it crashes and said me that "index is Out of Range."

但它崩溃了并告诉我“索引超出范围”。

采纳答案by dasblinkenlight

You need to sort the indexes that you would like to return from largest to smallest in order to avoid removing something at the wrong index.

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

foreach(int indice in lstIndices.OrderByDescending(v => v))
{
     lstOriginal.RemoveAt(indice);
}

Here is why: let's say have a list of five items, and you'd like to remove items at indexes 2and 4. If you remove the item at 2first, the item that was at index 4would be at index 3, and index 4would no longer be in the list at all (causing your exception). If you go backwards, all indexes would be there up to the moment when you're ready to remove the corresponding item.

原因如下:假设有一个包含五个项目的列表,并且您想删除索引2和处的项目4。如果您首先删除该项目2,则位于 index 的项目4将位于 index 3,并且 index4将根本不再在列表中(导致您的异常)。如果你倒退,所有索引都将存在,直到你准备好删除相应的项目。

回答by Omaha

The reason this is happening is because when you remove an item from the list, the index of each item after it effectively decreases by one, so if you remove them in increasing index order and some items near the end of the original list were to be removed, those indices are now invalid because the list becomes shorter as the earlier items are removed.

发生这种情况的原因是因为当您从列表中删除一个项目时,它之后的每个项目的索引实际上会减一,所以如果您以递增的索引顺序删除它们,并且原始列表末尾附近的一些项目将变为删除,这些索引现在无效,因为列表会随着较早的项目被删除而变短。

The easiest solution is to sort your index list in decreasing order (highest index first) and then iterate across that.

最简单的解决方案是按降序对索引列表进行排序(首先是最高索引),然后对其进行迭代。

回答by daryal

 lstIndices.OrderByDescending(p => p).ToList().ForEach(p => lstOriginal.RemoveAt((int)p));

As a side note, in foreach statements, it is better not to modify the Ienumerable on which foreach is running. The out of range error is probably as a result of this situation.

作为旁注,在 foreach 语句中,最好不要修改运行 foreach 的 Ienumerable。超出范围错误可能是这种情况的结果。

回答by SimpleVar

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

回答by alex.b

        var array = lstOriginal.ConvertAll(item => new int?(item)).ToArray();
        lstIndices.ForEach(index => array[index] = null);
        lstOriginal = array.Where(item => item.HasValue).Select(item => item.Value).ToList();

回答by phoog

How are you populating the list of indices? There's a much more efficient RemoveAllmethod that you might be able to use. For example, instead of this:

你如何填充索引列表?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

you could do this:

你可以这样做:

data.RemoveAll(item => SomeFunction(item));

This minimizes the copying of items to new positions in the array; each item is copied only once.

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

You could also use a method group conversion in the above example, instead of a lambda:

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

data.RemoveAll(SomeFunction);

回答by ghord

My in-place deleting of given indices as handy extension method. It copies all items only once so it is much more performant if large amount of indicies is to be removed.

我就地删除给定索引作为方便的扩展方法。它只复制所有项目一次,因此如果要删除大量索引,它的性能会更高。

It also throws ArgumentOutOfRangeExceptionin case where index to remove is out of bounds.

如果ArgumentOutOfRangeException要删除的索引超出范围,它也会抛出。

 public static class ListExtensions 
 {
    public static void RemoveAllIndices<T>(this List<T> list, IEnumerable<int> indices)
    {
        //do not remove Distinct() call here, it's important
        var indicesOrdered = indices.Distinct().ToArray();
        if(indicesOrdered.Length == 0)
            return;

        Array.Sort(indicesOrdered);

        if (indicesOrdered[0] < 0 || indicesOrdered[indicesOrdered.Length - 1] >= list.Count)
            throw new ArgumentOutOfRangeException();

        int indexToRemove = 0;
        int newIdx = 0;

        for (int originalIdx = 0; originalIdx < list.Count; originalIdx++)
        {
            if(indexToRemove < indicesOrdered.Length && indicesOrdered[indexToRemove] == originalIdx)
            {
                indexToRemove++;
            }
            else
            {
                list[newIdx++] = list[originalIdx];
            }
        }

        list.RemoveRange(newIdx, list.Count - newIdx);
    }
}