Home All Groups Group Topic Archive Search About

RemoveAt in foreach { ... }

Author
14 Oct 2006 8:20 AM
Hyun-jik Bae
Is there any efficient way doing Dictionary<>.RemoveAt in foreach {  ... }
routine?
For example, is this example safe or is there any recommended way?

foreach(KeyValuePair<int,int> a in mymap)
{
    if(a.Value!=GoodValue)
    {
         mymap.RemoveAt(a.Key);   // and continues the iteration
     }
}

Please reply. Thanks in advance.

Hyun-jik Bae

Author
14 Oct 2006 8:47 AM
Jon Slaughter
Show quote
"Hyun-jik Bae" <imays_NOSPAM_@paran.com> wrote in message
news:OkzUTm27GHA.4572@TK2MSFTNGP02.phx.gbl...
> Is there any efficient way doing Dictionary<>.RemoveAt in foreach {  ... }
> routine?
> For example, is this example safe or is there any recommended way?
>
> foreach(KeyValuePair<int,int> a in mymap)
> {
>    if(a.Value!=GoodValue)
>    {
>         mymap.RemoveAt(a.Key);   // and continues the iteration
>     }
> }
>

I don't remember exactly but I was reading something about this the other
day and I believe its not safe but there is a good way to fix it.

I'm not sure if it involes working on a temp copy or not though.

i.e., you could easily get around it by creating a shallow copy of mymap and
then working on that temp in the inner loop.


Sorry but thats the best I could do(I though I'd mention it just incase you
don't get to many replies).

Jon
Author
14 Oct 2006 12:22 PM
Göran_Andersson
You can't change the collection that you are looping through. Changing
the collection makes the enumerator invalid, and it will throw an
exception when you try to continue the loop.

One way to do it is to add the keys that you want to remove to a list,
then when you have looped through the dictionary, you loop throught the
list to remove the items from the dictionary.

Hyun-jik Bae wrote:
Show quote
> Is there any efficient way doing Dictionary<>.RemoveAt in foreach {  ... }
> routine?
> For example, is this example safe or is there any recommended way?
>
> foreach(KeyValuePair<int,int> a in mymap)
> {
>     if(a.Value!=GoodValue)
>     {
>          mymap.RemoveAt(a.Key);   // and continues the iteration
>      }
> }
>
> Please reply. Thanks in advance.
>
> Hyun-jik Bae
Author
14 Oct 2006 5:07 PM
Brian Gideon
Hyun-jik Bae,

Which collection are you using?  Dictionary does not have a RemoveAt
method.

As others have said removing an item will invalidate the enumerator.
It's better to figure out what you want to remove in one loop and then
actually remove in another.

Brian

Hyun-jik Bae wrote:
Show quote
> Is there any efficient way doing Dictionary<>.RemoveAt in foreach {  ... }
> routine?
> For example, is this example safe or is there any recommended way?
>
> foreach(KeyValuePair<int,int> a in mymap)
> {
>     if(a.Value!=GoodValue)
>     {
>          mymap.RemoveAt(a.Key);   // and continues the iteration
>      }
> }
>
> Please reply. Thanks in advance.
>
> Hyun-jik Bae
Author
14 Oct 2006 5:17 PM
Göran_Andersson
Brian Gideon wrote:
> Which collection are you using?  Dictionary does not have a RemoveAt
> method.

As he was feeding the key into the method, I assume that he means the
Remove method, that takes a key as argument. A RemoveAt method would
take an index instead of a key.
Show quote
:)
Author
15 Oct 2006 9:25 AM
Hyun-jik Bae
Sorry, that's my mistake. I should have shown Remove(), not RemoveAt().

Hyun-jik Bae

Show quote
"Brian Gideon" <briangid***@yahoo.com> wrote in message
news:1160845635.093200.277890@h48g2000cwc.googlegroups.com...
> Hyun-jik Bae,
>
> Which collection are you using?  Dictionary does not have a RemoveAt
> method.
>
> As others have said removing an item will invalidate the enumerator.
> It's better to figure out what you want to remove in one loop and then
> actually remove in another.
>
> Brian
>
> Hyun-jik Bae wrote:
>> Is there any efficient way doing Dictionary<>.RemoveAt in foreach {
>>  ... }
>> routine?
>> For example, is this example safe or is there any recommended way?
>>
>> foreach(KeyValuePair<int,int> a in mymap)
>> {
>>     if(a.Value!=GoodValue)
>>     {
>>          mymap.RemoveAt(a.Key);   // and continues the iteration
>>      }
>> }
>>
>> Please reply. Thanks in advance.
>>
>> Hyun-jik Bae
>
Author
15 Oct 2006 6:51 PM
Brian Gideon
Hyun-jik Bae,

No need to be sorry.  I was just wanting clarification.  Obviously, all
of the responses regarding RemoveAt are irrelevant now.  I think your
best option is to use the two loop method; one to figure out what you
want to remove and the other to actually remove them.

Brian


Hyun-jik Bae wrote:
Show quote
> Sorry, that's my mistake. I should have shown Remove(), not RemoveAt().
>
> Hyun-jik Bae
>
Author
14 Oct 2006 6:04 PM
Cor Ligthert [MVP]
Hyun-jik,

Although that there are possibilities, I never will use RemoveAt in a
foreach loop.

I will alway use to RemoveAt a For index with a bottom up loop.

Cor

Show quote
"Hyun-jik Bae" <imays_NOSPAM_@paran.com> schreef in bericht
news:OkzUTm27GHA.4572@TK2MSFTNGP02.phx.gbl...
> Is there any efficient way doing Dictionary<>.RemoveAt in foreach {  ... }
> routine?
> For example, is this example safe or is there any recommended way?
>
> foreach(KeyValuePair<int,int> a in mymap)
> {
>    if(a.Value!=GoodValue)
>    {
>         mymap.RemoveAt(a.Key);   // and continues the iteration
>     }
> }
>
> Please reply. Thanks in advance.
>
> Hyun-jik Bae
>
Author
14 Oct 2006 6:47 PM
Gaurav Vaish (www.EdujiniOnline.com)
> Although that there are possibilities, I never will use RemoveAt in a
> foreach loop.

I don't think there are any possibilities.
The enumerator would immediately become invalid....


Correct way:

1. Iterate through all entries.
2. Grab all those required in another list.
3. Remove all these "collected" (grabbed) entries from the original
list/collection.

The only way.


--
Happy Hacking,
Gaurav Vaish | www.mastergaurav.com
www.edujinionline.com
http://eduzine.edujinionline.com
-----------------------------------------
Author
14 Oct 2006 9:03 PM
Cor Ligthert [MVP]
>
> Correct way:
>
> 1. Iterate through all entries.
> 2. Grab all those required in another list.
> 3. Remove all these "collected" (grabbed) entries from the original
> list/collection.
>
> The only way.
>
No bottom up is easier,

For (int i = mycollection.count - 1;i > -1;i--)
    { if (whatever) removeAt(i);}

Cor
Author
15 Oct 2006 12:56 AM
Milosz Skalecki
or
while (dict.Count > 0)
        dict.RemoveAt(0);

--
Milosz Skalecki
MCP, MCAD


Show quote
"Cor Ligthert [MVP]" wrote:

> >
> > Correct way:
> >
> > 1. Iterate through all entries.
> > 2. Grab all those required in another list.
> > 3. Remove all these "collected" (grabbed) entries from the original
> > list/collection.
> >
> > The only way.
> >
> No bottom up is easier,
>
> For (int i = mycollection.count - 1;i > -1;i--)
>     { if (whatever) removeAt(i);}
>
> Cor

>
>
>
Author
15 Oct 2006 6:30 AM
Jon Skeet [C# MVP]
Milosz Skalecki <mily***@REMOVEITwp.pl> wrote:
> or
> while (dict.Count > 0)
>         dict.RemoveAt(0);

That only works if you're trying to clear the whole thing though - in
which case there are usually much simpler ways of doing it.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Author
15 Oct 2006 6:40 AM
Peter Duniho
"Cor Ligthert [MVP]" <notmyfirstn***@planet.nl> wrote in message
news:u7kiAQ97GHA.608@TK2MSFTNGP03.phx.gbl...
> No bottom up is easier,
>
> For (int i = mycollection.count - 1;i > -1;i--)
>    { if (whatever) removeAt(i);}

Just to be ornery, I'll point out that I like top down better:

int i = 0
while (i < mycollection.Count)
{
    if (!whatever)
    {
        i++;
        continue;
    }
    mycollection.RemoveAt(i);
}


:)

(I actually do like that better, because the code is IMHO more readable; too
many "minuses" and "offsets by one" in the bottom up version for my tastes)

Pete
Author
15 Oct 2006 9:01 PM
Michael D. Ober
The top down approach has another major benefit - it doesn't invalidate the
indexes of elements you haven't examed yet for removal.

Mike Ober.

Show quote
"Peter Duniho" <NpOeStPe***@NnOwSlPiAnMk.com> wrote in message
news:12j3m036h8fv8ff@corp.supernews.com...
> "Cor Ligthert [MVP]" <notmyfirstn***@planet.nl> wrote in message
> news:u7kiAQ97GHA.608@TK2MSFTNGP03.phx.gbl...
> > No bottom up is easier,
> >
> > For (int i = mycollection.count - 1;i > -1;i--)
> >    { if (whatever) removeAt(i);}
>
> Just to be ornery, I'll point out that I like top down better:
>
> int i = 0
> while (i < mycollection.Count)
> {
>     if (!whatever)
>     {
>         i++;
>         continue;
>     }
>     mycollection.RemoveAt(i);
> }
>
>
> :)
>
> (I actually do like that better, because the code is IMHO more readable;
too
> many "minuses" and "offsets by one" in the bottom up version for my
tastes)
>
> Pete
>
>
>
Author
16 Oct 2006 4:44 AM
Cor Ligthert [MVP]
Michael,

Feel free to use even 100 loops if you want. I think that one short loop
bottom up through the index is never to beat. Probably nobody has tested it
but are just telling that their long time taking approaches are the best.

This method is however not from me. Armin Zingler came with it I thought
about 3 years ago in the Visual Basic newsgroup, where all what is showed
now in this newsgroup was showed before that.

Now nobody active in the Visual Basic newsgroup will think on other than
bottom up methods for these problems, while they did before this top down,
with all those work around methods showed here.

Cor

Show quote
"Michael D. Ober" <ober***@.alum.mit.edu.nospam> schreef in bericht
news:mkxYg.14242$UG4.9725@newsread2.news.pas.earthlink.net...
> The top down approach has another major benefit - it doesn't invalidate
> the
> indexes of elements you haven't examed yet for removal.
>
> Mike Ober.
>
> "Peter Duniho" <NpOeStPe***@NnOwSlPiAnMk.com> wrote in message
> news:12j3m036h8fv8ff@corp.supernews.com...
>> "Cor Ligthert [MVP]" <notmyfirstn***@planet.nl> wrote in message
>> news:u7kiAQ97GHA.608@TK2MSFTNGP03.phx.gbl...
>> > No bottom up is easier,
>> >
>> > For (int i = mycollection.count - 1;i > -1;i--)
>> >    { if (whatever) removeAt(i);}
>>
>> Just to be ornery, I'll point out that I like top down better:
>>
>> int i = 0
>> while (i < mycollection.Count)
>> {
>>     if (!whatever)
>>     {
>>         i++;
>>         continue;
>>     }
>>     mycollection.RemoveAt(i);
>> }
>>
>>
>> :)
>>
>> (I actually do like that better, because the code is IMHO more readable;
> too
>> many "minuses" and "offsets by one" in the bottom up version for my
> tastes)
>>
>> Pete
>>
>>
>>
>
>
>
Author
16 Oct 2006 6:05 AM
Peter Duniho
"Cor Ligthert [MVP]" <notmyfirstn***@planet.nl> wrote in message
news:uExxO2N8GHA.4224@TK2MSFTNGP02.phx.gbl...
> Feel free to use even 100 loops if you want. I think that one short loop
> bottom up through the index is never to beat.

"Never to beat"?  In what respect?  In programming, there are far too many
competing goals for anyone to say one solution is the best one 100% of the
time.

I think it unlikely that if you are iterating through an entire indexed
collection and removing some subset of that collection, you'll see a
significant difference between various means of iteration, in the most
common cases.

If you're dealing with an array, and each removal requires that the
remaining elements in the array be copied down, then yes...starting at the
end will result in a slightly better performance.  However, unless you're
deleting most of the members of the array, you won't notice this difference.
The total data moved will only be a little less that way, and it ignores the
benefit of code clarity.

If performance is an issue, then the right way is to simply copy the
references to be preserved to a new array, and then just delete the entire
original.  This method will perform WAY better than either a top-down or
bottom-up in-place removal.  If performance is not an issue, then you can't
use performance as the sole measure of which method is better.

If you're dealing with a linked list, then removal by index is going to
perform poorly whichever end you start at, and there will be better
performance starting at the beginning (top-down) than the end (bottom-up).
A better way than using an index from either end would be to iterate through
the list by reference, so that removal operations have constant order.

> [...]
> This method is however not from me. Armin Zingler came with it I thought
> about 3 years ago in the Visual Basic newsgroup, where all what is showed
> now in this newsgroup was showed before that.

I hate to tell you this, but the question of removing elements from an
indexed array is so old, it's unlikely anyone could say who "came with it".
Neither your method nor mine is from either of us, nor originally from Armin
Zingler (whoever he is) and that fact goes without saying.  These concepts
predate .NET, Windows, and the PC.

> Now nobody active in the Visual Basic newsgroup will think on other than
> bottom up methods for these problems, while they did before this top down,
> with all those work around methods showed here.

What work-around methods?  The correct top-down method is equivalent to the
bottom-up method, and carries with it no greater degree of "work-around"
than the bottom-up method.

If "nobody active in the Visual Basic newsgroup will think on other than
bottom up methods for these problems", then that's because nobody in that
newsgroup understands that in programming, one size does not fit all.  In
reality, I doubt your assertion is true, but if it is, it's only proof of
one-dimensional thinking, rather than the validity of your claim that one
method is better than the other.

Pete
Author
16 Oct 2006 1:09 PM
Martin Z
Peter Duniho wrote:
Show quote
> "Cor Ligthert [MVP]" <notmyfirstn***@planet.nl> wrote in message
> news:u7kiAQ97GHA.608@TK2MSFTNGP03.phx.gbl...
> > No bottom up is easier,
> >
> > For (int i = mycollection.count - 1;i > -1;i--)
> >    { if (whatever) removeAt(i);}
>
> Just to be ornery, I'll point out that I like top down better:
>
> int i = 0
> while (i < mycollection.Count)
> {
>     if (!whatever)
>     {
>         i++;
>         continue;
>     }
>     mycollection.RemoveAt(i);
> }
>
>
> :)
>
> (I actually do like that better, because the code is IMHO more readable; too
> many "minuses" and "offsets by one" in the bottom up version for my tastes)
>
> Pete

Top-down or bottom-up, either way you have to worry.  Top-down can
easily produce a hairy starting fencepost error because it's less
commonly used.  Bottom-up can produce nastier logic errors on removal.

Imho, the DictionaryEntry<> should provide a "Remove" method that
abstracts away the hairiness of iteration/removal from a dict.
Likewise for lists, exposing a ListEntries enumerator that iterates
across ListEntry<> objects that provide a similar feature.
Author
14 Oct 2006 7:00 PM
Milosz Skalecki
enumerator is invalidated. use:

while (dict.Count > 0)
        dict.RemoveAt(0);
--
Milosz Skalecki
MCP, MCAD


Show quote
"Hyun-jik Bae" wrote:

> Is there any efficient way doing Dictionary<>.RemoveAt in foreach {  ... }
> routine?
> For example, is this example safe or is there any recommended way?
>
> foreach(KeyValuePair<int,int> a in mymap)
> {
>     if(a.Value!=GoodValue)
>     {
>          mymap.RemoveAt(a.Key);   // and continues the iteration
>      }
> }
>
> Please reply. Thanks in advance.
>
> Hyun-jik Bae
>
>
>

AddThis Social Bookmark Button