www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Is it legal to remove a key from associative array while iterating

reply realhet <real_het hotmail.com> writes:
Hi,

   //remap the result blobs
   foreach(k; res.blobs.keys){
     int p = map(k);
     if(p!=k){
       res.blobs[p].weight += res.blobs[k].weight;
       res.blobs.remove(k);
     }
   }

It boils down to:

   foreach(k; aa.keys) aa.remove(k);


Is it safe, or do I have to take a snapsot of the keys range like 
this? ->

   foreach(k; aa.keys.array) aa.remove(k); //this is 100% safe

I'm asking because I have no idea how the internal aa.keys range 
works. If it stores an index or a pionter inside, while I change 
the underlying structure of the aa, it could be a hazard...

Thanks in advance.
Aug 29 2021
parent reply Mike Parker <aldacron gmail.com> writes:
On Sunday, 29 August 2021 at 08:55:44 UTC, realhet wrote:

 Is it safe, or do I have to take a snapsot of the keys range 
 like this? ->
You shouldn't remove anything when iterating over `.keys` or `.values`. Use `.byKey` and `.byValue` instead to get ranges that are independent of the aa.
Aug 29 2021
next sibling parent realhet <real_het hotmail.com> writes:
On Sunday, 29 August 2021 at 09:02:52 UTC, Mike Parker wrote:
 On Sunday, 29 August 2021 at 08:55:44 UTC, realhet wrote:

 Is it safe, or do I have to take a snapsot of the keys range 
 like this? ->
You shouldn't remove anything when iterating over `.keys` or `.values`. Use `.byKey` and `.byValue` instead to get ranges that are independent of the aa.
I did a small test using .byKey, it's totally safe, just as you said. Thank You! ``` void main(){ int[int] aa = [1:10, 2:20, 3:30]; auto k1 = aa.keys; auto k2 = aa.byKey; aa.remove(2); writeln(typeof(k1).stringof); foreach(k; k1) writeln(k); writeln(typeof(k2).stringof); foreach(k; k2) writeln(k); } ```
Aug 29 2021
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/29/21 5:02 AM, Mike Parker wrote:
 On Sunday, 29 August 2021 at 08:55:44 UTC, realhet wrote:
 
 Is it safe, or do I have to take a snapsot of the keys range like 
 this? ->
You shouldn't remove anything when iterating over `.keys` or `.values`. Use `.byKey` and `.byValue` instead to get ranges that are independent of the aa.
This is exactly the opposite! The `.keys` property makes a *copy* of all the keys and puts them into an array. Same thing with `.values`. It is perfectly safe to remove anything from the associative array while iterating one of those arrays. The opposite is true for `.byKey` and `.byValue`. Those yield a range iterating over the actual data in the associative array. Removing an element while iterating one of those could potentially iterate over null or stale data, do not do this. While this might work out in some tests, eventually you will get bit by this, especially if you remove an element you are currently iterating. -Steve
Aug 29 2021
parent Mike Parker <aldacron gmail.com> writes:
On Sunday, 29 August 2021 at 11:09:28 UTC, Steven Schveighoffer 
wrote:

 This is exactly the opposite!
Sorry about that. I can't believe I mixed those up.
Aug 29 2021