www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Iterate over an array while mutating it?

reply "Anh Nhan" <anhnhan outlook.com> writes:
Hey guys,

I want to iterate over an array, while adding new entries, and 
have those in the iteration loop.

See here: https://gist.github.com/AnhNhan/9820226

The problem is that the foreach loop seemingly only iterates over 
the original array, not minding the newly added entries.

Does somebody have a solution or approach for the loop to pick up 
those new entries?

Anh Nhan
Mar 27 2014
next sibling parent reply "Infiltrator" <Lt.Infiltrator gmail.com> writes:
On Thursday, 27 March 2014 at 22:23:41 UTC, Anh Nhan wrote:
 I want to iterate over an array, while adding new entries, and 
 have those in the iteration loop.
Depending on what you're trying to do, perhaps you would be better off just adding the entries all at once instead of iterating the array?
 See here: https://gist.github.com/AnhNhan/9820226

 The problem is that the foreach loop seemingly only iterates 
 over the original array, not minding the newly added entries.
That's correct. foreach caches (which makes it faster) but means that you cannot mutate the range whilst iterating it.
 Does somebody have a solution or approach for the loop to pick 
 up those new entries?
Your best bet is probably a for loop: for(int i = 0; i < arr.length; i++) { arr ~= element; ... }
Mar 27 2014
parent reply "Anh Nhan" <anhnhan outlook.com> writes:
On Thursday, 27 March 2014 at 22:26:37 UTC, Infiltrator wrote:
 On Thursday, 27 March 2014 at 22:23:41 UTC, Anh Nhan wrote:
 I want to iterate over an array, while adding new entries, and 
 have those in the iteration loop.
Depending on what you're trying to do, perhaps you would be better off just adding the entries all at once instead of iterating the array?
 See here: https://gist.github.com/AnhNhan/9820226

 The problem is that the foreach loop seemingly only iterates 
 over the original array, not minding the newly added entries.
That's correct. foreach caches (which makes it faster) but means that you cannot mutate the range whilst iterating it.
 Does somebody have a solution or approach for the loop to pick 
 up those new entries?
Your best bet is probably a for loop: for(int i = 0; i < arr.length; i++) { arr ~= element; ... }
On Thursday, 27 March 2014 at 22:27:18 UTC, bearophile wrote:
 Anh Nhan:

 I want to iterate over an array, while adding new entries, and 
 have those in the iteration loop.
Don't iterate an array with foreach while you mutate it, even if you manage to make it work, the code is not clear. I suggest to use a C-style for loop with an index and specify in the code exactly what you want to do with the array and the index. The resulting code is clear and safe. Bye, bearophile
Ah, that the foreach caches the entries would make sense. I tried creating iterators Java-style, which did not pick up the new entries, too. It works with for-loops. Thanks for the explanations, they helped a lot. Anh Nhan
Mar 27 2014
parent "bearophile" <bearophileHUGS lycos.com> writes:
Anh Nhan:

 Ah, that the foreach caches the entries would make sense.
What does it mean "foreach caches the entries" for you? Foreach does very little. It is light syntax sugar over a normal for loop. Bye, bearophile
Mar 28 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Anh Nhan:

 I want to iterate over an array, while adding new entries, and 
 have those in the iteration loop.
Don't iterate an array with foreach while you mutate it, even if you manage to make it work, the code is not clear. I suggest to use a C-style for loop with an index and specify in the code exactly what you want to do with the array and the index. The resulting code is clear and safe. Bye, bearophile
Mar 27 2014
prev sibling next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Thursday, 27 March 2014 at 22:23:41 UTC, Anh Nhan wrote:
 Hey guys,

 I want to iterate over an array, while adding new entries, and 
 have those in the iteration loop.

 See here: https://gist.github.com/AnhNhan/9820226

 The problem is that the foreach loop seemingly only iterates 
 over the original array, not minding the newly added entries.

 Does somebody have a solution or approach for the loop to pick 
 up those new entries?
Reallocation will only happen if there isn't sufficient space left in the array. If you know the maximum number of elements in advance, you can reserve the necessary memory: import std.array; arr.reserve(arr.length + number_of_new_elements);
Mar 28 2014
prev sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Thu, 27 Mar 2014 22:23:40 -0000, Anh Nhan <anhnhan outlook.com> wrote:

 Hey guys,

 I want to iterate over an array, while adding new entries, and have  
 those in the iteration loop.

 See here: https://gist.github.com/AnhNhan/9820226

 The problem is that the foreach loop seemingly only iterates over the  
 original array, not minding the newly added entries.

 Does somebody have a solution or approach for the loop to pick up those  
 new entries?
Wrap the array in an adapter class/struct which implements opApply for foreach... import std.stdio; import std.conv; struct ForAdd(T) { T[] data; this(T[] _data) { data = _data; } void opOpAssign(string op : "~")(T rhs) { data ~= rhs; } int opApply(int delegate(ref T) dg) { int result = 0; for (int i = 0; i < data.length; i++) { result = dg(data[i]); if (result) break; } return result; } } int main(string[] args) { string[] test; for(int i = 0; i < 5; i++) test ~= to!string(i); auto adder = ForAdd!string(test); foreach(string item; adder) { writefln("%s", item); if (item == "2") adder ~= "5"; if (item == "4") adder ~= "6"; if (item == "5") adder ~= "7"; } return 0; } R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Mar 28 2014