Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List.forEach unable to modify element?

I'm attempting to create a list of lists to imitate the functionality of a 2D array in Dart, and I was having trouble for a while figuring out how to make it work.

I originally used List.forEach in order to create the lists and fill them, but after each loop, it's as if I never created the lists. Here's what that code looked like:

currentMap = new List<List<int>>(height);
currentMap.forEach((e) {
    e = new List<int>(width);
    e.forEach((f) {
        f = 1;
    });
});

Printing currentMap resulted in a list of null. Here's what I have now:

currentMap = new List<List<int>>(height);
for(int i = 0; i < height; i++) {
    currentMap[i] = new List<int>(width);
    for(int j = 0; j < width; j++) {
        currentMap[i][j] = 1;
    }
}

This works exactly as I expected it to.

I understand that this is probably a very basic issue, and I am assuming that forEach does not allow you to modify the element, but I wanted some confirmation on that, and the Dart API docs do not specify except with the phrase "apples the function f to each element..." which may just not be clear to me.

Also, I am aware of things like the List.filled() constructor -- this is just how I am starting to build towards other functionality.

EDIT: Okay, I think I understand now. Arguments are "pass-by-sharing" which means that a copy of a reference to the object is made. This means that you can modify a member of a mutable object that is pointed to by the argument (as follows):

void function(MyObject o) {
    o.x = 5;
}

but trying to change what o points to will not change the argument after exiting the function, such as this:

void function(MyObject o) {
    MyObject p = new MyObject();
    o = p;
}
like image 543
k_Reign Avatar asked Mar 05 '14 21:03

k_Reign


People also ask

Can you modify array in forEach?

Note that foreach does not modify the internal array pointer, which is used by functions such as current() and key(). It is possible to customize object iteration. In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.

Does forEach modify?

The forEach method of an array does not modify the array, it just iterates over it. When you change the argument in the callback function, that doesn't affect the array either. Also, forEach doesn't do anything with the return values from the callback.

Can you change values in a for each loop?

The for-each loop below cannot change the values in the array because only the loop variable value will change.

Does forEach change the original array?

forEach() does not mutate the array on which it is called.


3 Answers

Dart does not have variable references, all elements are passed as a reference to an object, not to a variable. (In other words, Dart is purely "call-by-sharing" like both Java and JavaScript).

That means that the e parameter to the forEach callback is just a normal local variable, and assigning to it has no effect outside the callback. The same goes for iterators: they return the value in the iterable, but it has no reference back to the iterable after that.

The double loop is what you want when you do "read-modify-write". You read a value from the list, modify it and store it back into the list using the list's index-set operator.

I know you know about List.filled, but just for other readers, I'll give the one-liner to create the two-dimensional array initialized to 1 values:

currentMap = new List.generate(height, (_) => new List.filled(width, 1));
like image 181
lrn Avatar answered Sep 28 '22 05:09

lrn


This is because e is only a reference to the List in currentMap not to a currentMap item.
You update a copy of the reference to a List, but this reference has no connection to currentMap.
After the loop, e just gets garbage collected.

like image 45
Günter Zöchbauer Avatar answered Sep 28 '22 04:09

Günter Zöchbauer


This is because of how an Enumerator works and I believe because the Enumerator is immutable You can't modify the collection items when it's being processed in a foreach... removing members and such.

See also:

http://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx

What is the best way to modify a list in a 'foreach' loop?

like image 32
Thomas Taylor Avatar answered Sep 28 '22 03:09

Thomas Taylor