Removing an element from a list or array

2014-08-06 Thread Patrick via Digitalmars-d-learn
I feel dumb.  I've been searching for how to do this, and each 
page or forum entry I read makes me more confused.


Let's say I have a list of values (Monday, Tuesday, Wednesday, 
Thursday, Friday).  I can store this list in an Slist, Dlist, 
Array etc -- any collection is fine.


I decide I want to remove Thursday from the list.

How?  I see that linearRemove is meant to do this, but that takes 
a range.  How do I get a range of 'Thursday'?




Re: Removing an element from a list or array

2014-08-06 Thread Jonathan M Davis via Digitalmars-d-learn

On Wednesday, 6 August 2014 at 19:01:26 UTC, Patrick wrote:
I feel dumb.  I've been searching for how to do this, and each 
page or forum entry I read makes me more confused.


Let's say I have a list of values (Monday, Tuesday, Wednesday, 
Thursday, Friday).  I can store this list in an Slist, Dlist, 
Array etc -- any collection is fine.


I decide I want to remove Thursday from the list.

How?  I see that linearRemove is meant to do this, but that 
takes a range.  How do I get a range of 'Thursday'?


Slicing a container gives you a range for that container, and 
it's that type that needs to be used to remove elements (either 
that, or that type wrapped with std.range.Take), since otherwise, 
the container wouldn't know which elements you were trying to 
remove - just their values.


You need to use std.algorithm.find to find the element that you 
want to remove, in which case, you have a range starting at that 
element (but it contains everything after it too). So, you used 
std.range.take to take the number of elements that you want from 
the range, and then you pass that result to linearRemove. e.g.


import std.algorithm;
import std.container;
import std.range;

void main()
{
auto arr = Array!string(Monday, Tuesday, Wednesday,
Thursday, Friday);
auto range = arr[];
assert(equal(range, [Monday, Tuesday, Wednesday,
 Thursday, Friday]));
auto found = range.find(Thursday);
assert(equal(found, [Thursday, Friday]));
arr.linearRemove(found.take(1));
assert(equal(arr[], [Monday, Tuesday, Wednesday, 
Friday]));

}

C++ does it basically the same way that D does, but it's actually 
one place where iterators are cleaner, because you can just pass 
the iterator to erase, whereas with a range, that would remove 
all of the elements after that element, which is why you need 
take, which makes it that much more complicated.


Using opSlice like that along with range-based functions like 
find which don't return a new range type will always be what 
you'll need to do in the general case, but it would definitely be 
nice if we added functions like removeFirst to remove elements 
which matched a specific value so that the simple use cases 
didn't require using find.


- Jonathan M Davis


Re: Removing an element from a list or array

2014-08-06 Thread Patrick via Digitalmars-d-learn

Thank you, that is a great sample.

On Wednesday, 6 August 2014 at 19:41:50 UTC, Jonathan M Davis 
wrote:

On Wednesday, 6 August 2014 at 19:01:26 UTC, Patrick wrote:
I feel dumb.  I've been searching for how to do this, and each 
page or forum entry I read makes me more confused.


Let's say I have a list of values (Monday, Tuesday, Wednesday, 
Thursday, Friday).  I can store this list in an Slist, Dlist, 
Array etc -- any collection is fine.


I decide I want to remove Thursday from the list.

How?  I see that linearRemove is meant to do this, but that 
takes a range.  How do I get a range of 'Thursday'?


Slicing a container gives you a range for that container, and 
it's that type that needs to be used to remove elements (either 
that, or that type wrapped with std.range.Take), since 
otherwise, the container wouldn't know which elements you were 
trying to remove - just their values.


You need to use std.algorithm.find to find the element that you 
want to remove, in which case, you have a range starting at 
that element (but it contains everything after it too). So, you 
used std.range.take to take the number of elements that you 
want from the range, and then you pass that result to 
linearRemove. e.g.


import std.algorithm;
import std.container;
import std.range;

void main()
{
auto arr = Array!string(Monday, Tuesday, Wednesday,
Thursday, Friday);
auto range = arr[];
assert(equal(range, [Monday, Tuesday, Wednesday,
 Thursday, Friday]));
auto found = range.find(Thursday);
assert(equal(found, [Thursday, Friday]));
arr.linearRemove(found.take(1));
assert(equal(arr[], [Monday, Tuesday, Wednesday, 
Friday]));

}

C++ does it basically the same way that D does, but it's 
actually one place where iterators are cleaner, because you can 
just pass the iterator to erase, whereas with a range, that 
would remove all of the elements after that element, which is 
why you need take, which makes it that much more complicated.


Using opSlice like that along with range-based functions like 
find which don't return a new range type will always be what 
you'll need to do in the general case, but it would definitely 
be nice if we added functions like removeFirst to remove 
elements which matched a specific value so that the simple use 
cases didn't require using find.


- Jonathan M Davis