digitalmars.D.learn - Iterate over an array while mutating it?
- Anh Nhan (9/9) Mar 27 2014 Hey guys,
- Infiltrator (8/15) Mar 27 2014 Depending on what you're trying to do, perhaps you would be
- Anh Nhan (8/34) Mar 27 2014 Ah, that the foreach caches the entries would make sense. I tried
- bearophile (5/6) Mar 28 2014 What does it mean "foreach caches the entries" for you? Foreach
- bearophile (8/10) Mar 27 2014 Don't iterate an array with foreach while you mutate it, even if
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (6/14) Mar 28 2014 Reallocation will only happen if there isn't sufficient space
- Regan Heath (43/51) Mar 28 2014 Wrap the array in an adapter class/struct which implements opApply for
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
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
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:On Thursday, 27 March 2014 at 22:27:18 UTC, bearophile 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; ... }Anh Nhan: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 NhanI 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
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
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
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
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