std.algorithm.remove strange behavior (removing items for the dynamic array)

Jonathan M Davis jmdavisProg at gmx.com
Thu May 10 20:18:23 PDT 2012


On Friday, May 11, 2012 04:45:18 mezozoysky wrote:
> Hello!
> I'm noticed that something non-obvious is happening with my code
> today and i've found that the trouble somewhere close to the
> removing items from the dynamic arrays e.i. close to
> std.algorithm.remove function in this case.
> 
> I wrote a little test example using this function:
> 
> 
> module test.app;
> 
> import std.stdio: writefln;
> import std.algorithm;
> 
> int main(string[] args) {
> 
> 	int[] a = [2, 4, 8, 16, 32, 64, 128];
> 	writefln("a before: %s", a);
> 	a.remove(3);
> 	writefln("a after : %s", a);
> 	a.remove(1);
> 	writefln("a after2: %s", a);
> 
> 	return 0;
> }
> 
> 
> ...and got the following output:
> 
> 
> a before: [2, 4, 8, 16, 32, 64, 128]
> a after : [2, 4, 8, 32, 64, 128, 128]
> a after2: [2, 8, 32, 64, 128, 128, 128]
> 
> 
> I'm confused.
> Please tell me is it normal behavior of this function or is it a
> bug?
> Maybe i'm doing something wrong?
> Maybe i need another "remove" or maybe it's normal to use slicing
> to remove array's items (like a = a[0..i] ~ [i+1..$]) ?
> 
> Thanx for attention.
> 
> P.S. I'm sorry if my english confuses you.

No. As the documentation for remove explains, this is completely expected. 
remove removes elements from _the range_, not the container. It can't remove 
elements from the container (regardless of the container or range type), 
because it doesn't understand anything about the container. It shifts the 
elements forward in the range and returns a range which is reduced in length 
by the number of elements removed, but the original range is not reduced in 
size, nor is the underlying container reduced in size (all of which is 
slightly more confusing with dynamic arrays, because the range _is_ the 
container, which is not the case in general). Also, some ranges don't even 
_have_ an underlying container, so remove _definitely_ can't remove anything 
from the container itself - only shift elements. C++'s erase function has the 
exact same problem.

If you would just assign the result back to a, then your example would work as 
you expect.

import std.stdio: writefln;
import std.algorithm;

int main(string[] args)
{
    int[] a = [2, 4, 8, 16, 32, 64, 128];
    writefln("a before: %s", a);
    a = a.remove(3);
    writefln("a after : %s", a);
    a = a.remove(1);
    writefln("a after2: %s", a);

    return 0;
}

a before: [2, 4, 8, 16, 32, 64, 128]
a after : [2, 4, 8, 32, 64, 128]
a after2: [2, 8, 32, 64, 128]

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list