1

I'm attempting to run the following foreach loop so I can remove a specific entry.

textMap.results.forEach((element) {
   textMap.results.removeAt(**element.KEY**);
   print(element.KEY)
}

Is it possible to reference the index/key of a foreach loop?? I've tested this with a basic iterator but if the list contains multiple entries that needs to be deleted then the index becomes out of sync once an initial item gets removed. Hence why I am looking for an index/key

ukholly
  • 45
  • 1
  • 8
  • So you basically want a counter for each element in the loop? – MendelG Jul 12 '21 at 21:38
  • not quite as I've tested this with a basic iterator but if the list contains multiple entries that will be deleted then the index becomes out of sync once an item gets removed. Hence when I am looking for an index/key – ukholly Jul 12 '21 at 22:10

1 Answers1

3

First, avoid using Iterable.forEach except for trivial cases. If you want element indices, just use a normal looping construct (e.g. for, while). Also see https://stackoverflow.com/a/65420010/.

In your example code, you unconditionally remove each item, so you could just call List.clear() at the end, which would be much simpler and more efficient. That should be O(1).

If you don't want to remove all items and instead need to conditionally remove multiple items, there are a few ways you could do it.

  • Use List.removeWhere if possible. I expect this to be O(n) with respect to the length of the list.

  • Process the items from last to first so that removing an element from the list does not affect iteration:

    for (var i = textMap.results.length - 1; i >= 0; i -= 1) {
      print(textMap.results[i]); // Do something with the element.
      if (shouldRemove(textMap.results[i])) {
        textMap.results.removeAt(i);
      }
    }
    
  • If you must process the elements in order, you can first collect a list of indices to remove and then remove them separately:

    var indicesToRemove = <int>[];
    for (var i = 0; i < textMap.results.length; i += 1) {
      print(textMap.results[i]); // Do something with the element.
      if (shouldRemove(textMap.results[i])) {
        indicesToRemove.add(i);
      }
    }
    // Remove in reverse order so that removing items does not affect
    // unprocessed indices.
    for (var index in indicesToRemove.reversed) {
      textMap.results.removeAt(index);
    }
    
  • Alternatively use a while loop that conditionally increments the list index:

    var i = 0;
    while (i < textMap.results.length) {
      print(textMap.results[i]); // Do something with the element.
      if (shouldRemove(textMap.results[i])) {
        textMap.results.removeAt(i);
        // Iterate again at the same index.
        continue;
      }
      i += 1;
    }
    

The last three approaches would be O(m*n) where n is the length of the list and m is the number of items to remove.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204