0

i have the following List

List myList = [
{'name':'Alex'},
{'name':'Ali'},
{'name':'jack'},
{'name':'Alex'},
{'name':'Alex'},
];

Now i want update all item that the name == 'Alex' to 'Andy'

so i tried the following

int wantedIndex =  myList.indexWhere((element) =>  element['name']=='Alex');
  myList[wantedIndex] = {'name':'Andy'} ;

since the indexWhere is only get the first target index so it will update one item only.

so How could i achieve this with all item that == 'Alex' ?

  • Just loop over your list and for each one check if they have the name Alex, and if they do then set the name to Andy. – mmcdon20 May 27 '23 at 00:20
  • it is the same thing with loop , how you will set the name to Andy to all item that == the condition ? unless if you mean to use integer and increase it per loop time then update it .. i don't think it is good way – Yousuf Essa May 27 '23 at 00:33
  • `for (var map in myList) { if (map['name'] == 'Alex') { map['name'] = 'Andy'; } }` – jamesdlin May 27 '23 at 01:35
  • in this code you only edit local loop value which not be added the new value to myList – Yousuf Essa May 27 '23 at 01:54
  • 1
    @YousufEssa Perhaps you should try it first. It *mutates* the list elements. – jamesdlin May 27 '23 at 04:15
  • You are right !! but how it update original list too if we only change the local value in loop ?? because i tried too with List but does not update to original list like if it was List – Yousuf Essa May 28 '23 at 14:07
  • @YousufEssa You're confusing this with *reassigning* a local variable, which the code in my comment is not doing. On each iteration, the local variable is a *reference* to a `Map` object that is an element of the `List`. The code is *mutating* that `Map` object. It wouldn't work with a `List` because Dart `String`s are immutable and therefore would require mutating the `List` itself. – jamesdlin May 28 '23 at 14:36
  • @YousufEssa I notice that you keep saying "local value", which maybe is why you're confused. The *value* of a Dart variable is a *reference* to an object. On the *n*th iteration of the loop, the local variable `map` would be a reference to the same object that `myList[n]` refers to. `map` is a copy of a reference, not a copy of the `Map` object itself. If this is still unclear I can draw a box-and-pointer diagram. – jamesdlin May 28 '23 at 15:12
  • "local value", which maybe is why you're confused. "5 years studying Dart . you will not believe if i said to you this is the first time to me i know this information . don't know if i should cry now or be happy to get this info lol .. thanks a lot .. and yes please if you can draw a box-and-pointer diagram as answer ti accept it and for more understand too .. – Yousuf Essa May 28 '23 at 17:45

3 Answers3

1

A simple for-in loop would suffice:

for (var map in myList) {
  if (map['name'] == 'Alex') {
    map['name'] = 'Andy';
  }
}

Based on your comments, you are confused about how that code mutates the elements of myList through a local variable.

           +-----+-----+-----+-----
myList --> |  o  |  o  |  o  | ... 
           +--|--+--|--+--|--+-----
              |     |     |
              |     |     +---------------+
              |     +-----------+         |
              v                 |         v
          {'name': 'Alex'}      |     {'name': 'jack'}
              ^                 v
              |             {'name': 'Ali'}
      map ----+

All variables are references to objects. myList is a reference to a List object that internally stores an array of references to Map objects. As you iterate through myList, the loop's local map variable will refer to those same Map objects. (Note that no objects are copied. Dart does not have copy constructors and therefore cannot create copies of arbitrary objects.)

If you reassign that local map variable to something else, then that would just make map refer to some other object and would not affect myList or any of its elements. However, calling mutators through map (such as Map.operator []=) would mutate the referenced Map objects, the same objects referenced by the list elements.

Related: What is the true meaning of pass-by-reference in modern languages like Dart?

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
0

You could use map method.

myList.map((item) {
  if (item['name'] == 'Alex') item['name'] = 'Andy';
}).toList();

print(myList); // [{name: Andy}, {name: Ali}, {name: jack}, {name: Andy}, {name: Andy}]
debug_ing
  • 476
  • 3
  • 13
  • 2
    This is inappropriate for `List.map`, which is meant for a functional style. Callbacks with side-effects are bad form, and you unnecessarily create a new `List` that you don't need. This is more appropriate for `List.forEach`, or even better, a `for-in` loop as I suggested in the question comments. – jamesdlin May 27 '23 at 04:22
0

We need to be a bit careful. Your code

int wantedIndex =  myList.indexWhere((element) =>  element['name']=='Alex');
myList[wantedIndex] = {'name':'Andy'} ;

is actually replacing any map with key "name" set to "Alex" with a new map with key "name" set to "Andy". Let's say that the original datum was {'name': 'Alex', 'age': 'ten'}, your code would replace it with {'name': 'Andy'}, and the "age" data would be lost. That might or might not matter, depending on the context. Also, your code is assuming that there is such an element in the list; if there isn't, then indexWhere returns -1, which could be an issue.

For this type of problem, using a recursive solution is often helpful. For example, using the logic you used in your post:

void update(List<Map<String, String>> data) {
  final index = data.indexWhere((element) => element["name"] == "Alex");
  if (index != -1) update(data..[index]["name"] = "Andy");
}

(Notice, if there are other key-value pairs in the data, they are not lost, and if there are no matches, there is no problem with indexing.)

Then we could just do:

update(myList);
Richard Ambler
  • 4,816
  • 2
  • 21
  • 38