Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# RemoveRange()方法在列表中如何工作<>;?_C#_.net_List_Ienumerable - Fatal编程技术网

C# RemoveRange()方法在列表中如何工作<>;?

C# RemoveRange()方法在列表中如何工作<>;?,c#,.net,list,ienumerable,C#,.net,List,Ienumerable,如标题所示。我知道它可能会在删除项目之前和之后合并2个子列表,但当删除最后一个元素时,该方法的行为如何?换句话说:它是否以某种方式复制了位于删除索引之前的所有元素?我只是好奇在一个巨大的列表(比如说5000个元素)上使用RemoveAnge只删除最后2个元素的性能 若它进行了复制,那个么有并没有办法更改一些设置列表大小的内部变量(并将其余分配的元素视为垃圾) 我只找到了一个信息,这是一个O(n)复杂度算法,但我不确定这个案例中的“n”是一个列表大小,还是一个要删除的项目数 很高兴得到任何提示。它

如标题所示。我知道它可能会在删除项目之前和之后合并2个子列表,但当删除最后一个元素时,该方法的行为如何?换句话说:它是否以某种方式复制了位于删除索引之前的所有元素?我只是好奇在一个巨大的列表(比如说5000个元素)上使用RemoveAnge只删除最后2个元素的性能

若它进行了复制,那个么有并没有办法更改一些设置列表大小的内部变量(并将其余分配的元素视为垃圾)

我只找到了一个信息,这是一个O(n)复杂度算法,但我不确定这个案例中的“n”是一个列表大小,还是一个要删除的项目数


很高兴得到任何提示。

它将在要删除的项目范围结束后获取每个项目,并在列表中按已删除的项目数上移。就性能影响而言,在移动的项目范围结束后,每个项目将有一份副本。这意味着从末尾移除时它的性能最好(将是O(1)),从开头移除时它的性能最差(O(n))

作为一个例子,考虑下面的列表:

index - value 0 - A 1 - B 2 - C 3 - D 4 - E 5 - F 6 - G 索引值 0-A 1-B 2-C 三维 4-E 5-F 6-G 如果我们调用
RemoveRange(2,2)
,那么我们将从索引2开始删除两项,因此我们将删除C和D

这意味着E需要复制到索引2,F需要复制到索引3,G需要复制到索引4。删除最后一个项目后,每个项目都有一个复制操作

请注意,由于您可以将整个内存块“向上”移动两次,因此在实践中,这比单独复制每个项更有效。对于计算机内存来说,将整个内存块向上移动一定数量的字节要比将大量的小内存段移动到不同的任意位置容易得多。但它将具有相同的渐进复杂性。

列表
只是一个数组的包装,在下面的代码中称为
\u items
。数组中的插槽可能比列表中的项目多,因此使用
\u size
跟踪实际有效的插槽数量。当您执行
删除范围(索引、计数)

_size -= count;
if (index < _size)
    Array.Copy(_items, index + count, _items, index, _size - index);
Array.Clear(_items, _size, count);
\u size-=计数;
如果(索引大小)
复制(_项,索引+计数,_项,索引,_大小-索引);
数组。清除(_项、_大小、计数);
…它将超出范围的项目复制到现在为空的空间中,并清除旧项目

如果要删除一个大列表开头附近的区域,那么成本与列表的大小成正比,因为有太多的内容需要向下移动


如果要删除大列表末尾附近的大范围,则复制成本较低,但清除成本较高,因此成本将与删除范围的大小成比例。

“此方法是一种O(n)操作,其中n为计数。”“项目将被删除,列表中紧随其后的所有元素的索引将按计数减少。”“请注意,这会导致列表的其余部分需要向下移动以填补空白,这可能是非常重要的。但是,它不需要重新分配列表,因为列表的大小可能在缩小,而不是在增长。“算了吧,你以为那个伯爵就是要被除名的数字。从10人名单中删除2人所需的时间与从100万人名单中删除2人所需的时间相同。如果单击文档中的计数,它将链接列表计数。@除非从列表末尾删除,否则这不是真的。如果要从列表的开头删除,那么将内存中的8个项目向上移动两个项目与将内存中的1999998个项目向上移动两个项目的区别就在于此。这两个元素并不相等。顺便说一句,一个包含5000个元素的列表并不庞大。在正常情况下大约只有20或40 kB(对于列表本身,而不是其中的数据)。@Servy但是一个10的列表只能是一个10的列表。文档中的该计数是列表计数,因为它以0(N)为界。但仍然是很好的答案+1。请你们再深入一点,解释一下为什么在第二种情况下清算费用昂贵?据我所知,我们必须只清除数组中受影响的元素,其数量没有
\u size
\u items.Length
大列表的情况下大。例如,如果您正在删除大列表中靠近开始或接近结束的小范围。@Jodrell可能不会。当使用链表时,内存局部性的丢失会导致非常差的性能,即使对于诸如迭代链表之类的简单任务也是如此。虽然它的许多操作的大O值都很低,但在大多数实际情况下,链表是一种不常见的净胜利。@Eric:谢谢你的回答,但是你能解释一下你描述的最后一种情况吗?在我看来,复制后,所有要清除的内容都将放在数组的新长度索引之外,因此不需要清除任何内容。@Tarec如果列表未被清除,并且它保留引用类型或结构,并且引用类型带有字段,它们不能被垃圾收集。@Tarec:Grand User是正确的;假设它是一个包含大量内存的对象的长列表,并且您删除了大量对象。你会期望它们在下一次收集时被回收。垃圾收集器只看到一个数组;它不知道没有人会再访问它们。清除内存让列表告诉GC这些引用将不再被列表使用。