www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Removing an element from a list or array

reply "Patrick" <pmeade gmail.com> writes:
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'?
Aug 06 2014
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Aug 06 2014
parent "Patrick" <pmeade gmail.com> writes:
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
Aug 06 2014