看起来你正在寻找算法的解释,所以我会尝试解释它。
您正在“重写”数组。考虑让游标遍历读取数据的数组,同时让游标在其后面写入值。在这种情况下,“读取”光标可以是 foreach 循环或带有索引器的 for 循环。
测试数据:
[12,34,56,34,78]
我们想删除34,我们从位置0(即values[0])的两个游标开始,“newLength = 0”代表“新”数组的长度,因此“写”游标的位置目前居住:
[12,34,56,34,78]
^r
^w
newLength: 0
读取的第一个元素 12 不匹配,因此我们将该元素包含在“新”数组中,方法是将其写入数组中由“新”数组的当前长度表示的位置(开始, 长度为 0,所以是 values[0]。在这种情况下,我们正在向该元素写入相同的值,所以没有任何变化,我们通过增加“新”数组的长度将写入光标移动到下一个位置
[12,34,56,34,78]
^r
^w
newLength: 1
现在下一个元素确实匹配要删除的值,所以我们不想将它包含在新数组中。我们通过不增加“新”数组的长度并在读取光标移动到下一个元素时将写入光标留在原处来做到这一点:
[12,34,56,34,78]
^r
^w
newLength: 1
如果这个数组只有两个元素,我们就完成了,数组中的值没有改变,但返回的长度只有1。随着我们有更多的元素,让我们继续看看会发生什么。我们读取56,它与要删除的值不匹配,因此我们将其“写入”到新“长度”指定的位置,然后增加长度:
[12,56,56,34,78]
^r
^w
newLength: 2
现在我们读取了一个匹配的值,所以我们跳过写入它:
[12,56,56,34,78]
^r
^w
newLength: 2
而且最终的值不匹配,所以我们写在“length”指定的位置,并增加长度:
[12,56,78,34,78]
^r
^w
newLength: 3
“读取”光标现在超出了数组的长度,所以我们完成了。新的“长度”值现在是3,因为我们向数组“写入”了三个值。将数组与newLength 值结合使用,在功能上会产生“新”数组[12,56,78]。
这是@TheGeneral 使用指针的功能正确但不安全的安全实现:
public static int DoStuffSafely( int[] values, int valueToRemove, int length )
{
var newLength = 0;
// ~13.5% slower than @TheGeneral's unsafe implementation
foreach( var v in values )
{
// if the value matches the value to remove, skip it
if( valueToRemove != v )
{
// newLength tracks the length of the "new" array
// we'll set the value at that index
values[ newLength ] = v;
// then increase the length of the "new" array
++newLength;
// I never use post-increment/decrement operators
// it requires a temp memory alloc that we toss immediately
// which is expensive for this simple loop, adds about 11% in execution time
}
}
return newLength;
}
编辑:为@Richardissimo
values[ newLength ] = v;
00007FFBC1AC8993 cmp eax,r10d
00007FFBC1AC8996 jae 00007FFBC1AC89B0
00007FFBC1AC8998 movsxd rsi,eax
00007FFBC1AC899B mov dword ptr [r8+rsi*4+10h],r11d
++newLength;
00007FFBC1AC89A0 inc eax
values[ newLength++ ] = v;
00007FFBC1AD8993 lea esi,[rax+1]
00007FFBC1AD8996 cmp eax,r10d
00007FFBC1AD8999 jae 00007FFBC1AD89B3
00007FFBC1AD899B movsxd rax,eax
00007FFBC1AD899E mov dword ptr [r8+rax*4+10h],r11d
00007FFBC1AD89A3 mov eax,esi