remove from array
Frits van Bommel
fvbommel at REMwOVExCAPSs.nl
Tue Feb 27 16:39:29 PST 2007
Thorsten wrote:
>> <totaly untested code>
>>
>> T[] Remove(T)(T[] arr, int i)
>> {
>> return i==arr.length-1 ? arr[0..$-1] : arr[0..i] ~ arr[i+1 .. $];
>> }
>
> Sorry, I tried that, and it is too expensive !!
> Because it creates about 3 temporary instances.
Nonsense.
First of all, only one of the last two clauses is even evaluated.
And second, only the second clause allocates, and even then only once.
Slicing an array doesn't create a copy, it just creates a new (length,
pointer) pair. Only the '~' allocates, and this is not a temporary but
the return value.
That function might be improved a bit by also returning a plain slice
for the case i == 0, but with that change it's perfectly fine as long as
copy-on-write is acceptable.
If you are certain no copies of the original array (including
overlapping arrays) will be kept, you can use something like your
suggestion:
> I would say :
>
> void Remove(T)(inout T[] arr, int i)
> {
> for(uint j = i;j < arr.length-1;++j)
> arr[j] = arr[j+1];
> arr.length = arr.length - 1;
> }
>
> can someone accelerate this ???
Using memmove to replace the loop has already been suggested, that
should usually be fast.
Though consider checking if the removed element is closer to the
beginning of the array, and if so moving the first part instead of the
second part followed by "arr = arr[1 .. $]":
---
// warning: untested code
void Remove(T)(inout T[] arr, int i)
{
if (i < (arr.length / 2)) {
for(uint j = i; j > 0; --j)
arr[j] = arr[j-1];
arr = arr[1 .. $];
} else {
for(uint j = i; j < arr.length-1; ++j)
arr[j] = arr[j+1];
arr.length = arr.length - 1;
}
}
---
where the for loops may also be replaced by memmove.
This should perform less memory operations for first-half removals.
However, this has the nasty side effect that using ~= on the resulting
array will _reallocate_.
More information about the Digitalmars-d
mailing list