www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - std.algorithm.remove strange behavior (removing items for the dynamic

reply "mezozoysky" <neferegio gmail.com> writes:
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.
May 10 2012
next sibling parent "mezozoysky" <neferegio gmail.com> writes:
I almost forgot:
i'm using DMD 2.059 on Debian testing (AMD64).

On Friday, 11 May 2012 at 02:45:20 UTC, 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.

May 10 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
May 10 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-11 05:18, Jonathan M Davis wrote:
 ...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.

Is it supposed to change the underlying array like that? It doesn't print the original sequence. -- /Jacob Carlborg
May 10 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-05-11 08:24, Jonathan M Davis wrote:
 On Friday, May 11, 2012 08:15:45 Jacob Carlborg wrote:

 Is it supposed to change the underlying array like that? It doesn't
 print the original sequence.

Yes. To remove an element, it shifts all of the elements to the right of that element over by one. It just doesn't change the elements on the end when it shifts elements over, so the last element gets duplicated. - Jonathan M Davis

Ok, I see. -- /Jacob Carlborg
May 10 2012
prev sibling next sibling parent "mezozoysky" <neferegio gmail.com> writes:
On Friday, 11 May 2012 at 03:18:41 UTC, Jonathan M Davis wrote:
 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

Thank you, Jonathan! Thanks to you I saw that the documentation for std.algorithm contains useful information about "remove", not just the phrase "Remove current item from the target.", which opens when you click on the "remove" link at the top of the page :) Really thank you. It works for me.
May 10 2012
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, May 11, 2012 08:15:45 Jacob Carlborg wrote:
 On 2012-05-11 05:18, Jonathan M Davis wrote:
 ...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.

Is it supposed to change the underlying array like that? It doesn't print the original sequence.

Yes. To remove an element, it shifts all of the elements to the right of that element over by one. It just doesn't change the elements on the end when it shifts elements over, so the last element gets duplicated. - Jonathan M Davis
May 10 2012