How to stop Dart's .forEach()?

Dart

Dart Problem Overview


List data = [1, 2, 3];
data.forEach((value) {
  if (value == 2) {
    // how to stop?
  }
  print(value);
});

I tried return false; which works in jQuery, but it does not work in Dart. Is there a way to do it?

Dart Solutions


Solution 1 - Dart

You can also use a for/in, which implicitly uses the iterator aptly demonstrated in the other answer:

List data = [1,2,3];

for(final i in data){
  print('$i');
  if (i == 2){
    break;
  }
}

Solution 2 - Dart

It is also possible to implement your example using forEach() and takeWhile().

var data = [1, 2, 3];
data.takeWhile((val) => val != 2).forEach(print);

Solution 3 - Dart

Breaking a List

List<int> example = [ 1, 2, 3 ];

for (int value in example) {
  if (value == 2) {
    break;
  }
}

Breaking a Map

If you're dealing with a Map you can't simply get an iterator from the given map, but you can still use a for by applying it to either the values or the keys. Since you sometimes might need the combination of both keys and values, here's an example:

Map<String, int> example = { 'A': 1, 'B': 2, 'C': 3 };

for (String key in example.keys) {
  if (example[key] == 2 && key == 'B') {
    break;
  }
}

Note that a Map doesn't necessarily have they keys as [ 'A', 'B', 'C' ] use a LinkedHashMap if you want that. If you just want the values, just do example.values instead of example.keys.

Alternatively if you're only searching for an element, you can simplify everything to:

List<int> example = [ 1, 2, 3 ];
int matched = example.firstMatching((e) => e == 2, orElse: () => null);

Solution 4 - Dart

The callback that forEach takes returns void so there is no mechanism to stop iteration.

In this case you should be using iterators:

void listIteration() {
  List data = [1,2,3];

  Iterator i = data.iterator;

  while (i.moveNext()) {
    var e = i.current;
    print('$e');
    if (e == 2) {
      break;
    }
  }
}

Solution 5 - Dart

Dart does not support non-local returns, so returning from a callback won't break the loop. The reason it works in jQuery is that each() checks the value returned by the callback. Dart forEach callback returns void.

http://docs.jquery.com/Core/each

Solution 6 - Dart

based on Greg Lowe post, I used where for my project and also it works.

var data = [1, 2, 3];
data.where((val) => val != 2).forEach(print);

Solution 7 - Dart

Using Multiple Loop

Break Outer Loop

OUTER: for (var i = 0; i < m.length; i++) {
  for (var j = 0; j < m[i].length; j++) {
    if (m[i][j] < 0) {
      print("Negative value found at $i,$j: ${m[i][j]}");
      break OUTER;
    }
  }
}

Continue Outer Loop

  outer: for (var v in a) {
    for (var w in b) {
      if (w == v) continue outer;
    }
    print(v);
  }

Solution 8 - Dart

You can use for and indexOf

 for (var number in id) {
    var index = id.indexOf(number);

    print('Origin forEach loop');

    for (int i = 0; i < 1; i++) {
      print("for loop");
    }

    break;
  }

Solution 9 - Dart

Here is a full sample by for-in loop, that close to forEach style.

void main(){
  var myList = [12, 18, 24, 63, 84,99];
  
  myList.forEach((element) {
   print(element);
   if (element ==24); //break; // does not work
  });
     
 for(var element in myList) {
    print(element);
    if (element==24) break;
   } 
} 

Solution 10 - Dart

Somebody suggest where() but it is not a general replacement for forEach() with break capability

(where is however a correct replacement for the use case showed in the example of the question. I, on the other hand, focus on the question in the title)

The functionality of foreach() but with an equivalent of break, is given by any(): to continue the loop you return false, to stop you return true; the result of any() can be ignored. I think it is more similar to each() in jquery (but in dart to stop you return true).

To have a loop with the index, but also the possibility in case of break the loop, I use the following extension:

extension IterableUtils<E> on Iterable<E> {

  /**
    Similar to Iterable.forEach() but:
    - with an index argument
    - with the optional capacity to break the loop, returning false
      Note: as for the return clause, you can omit it, as with forEach()
   */
  void forEachIndexed(Function(E element, int index) f) {
    int index = 0;
    for (E element in this) {
      if (f(element, index) == false) break;
      index++;
    }
  }
}
Example:
void main() {

  List list = ["a", "b", "c"];

  list.forEachIndexed((element, index) {
    print("$index: $element");

    //Optional:
    if (element == "b") return false; //break
  });
}

Solution 11 - Dart

You CAN empty return from a forEach to break the loop;

List<int> data = [1, 2, 3];
int _valueToBePrinted; 

data.forEach((value) {
  if (value == 2) {
    _valueToBePrinted = value;
    return;
  }
});
// you can return something here to
// return _valueToBePrinted;
print(value);

anyway you shouldn't...

the catch is, you can't return anything in the entire forEach loop

//This don't work
data.forEach((value) {
  if (value == 2) {
    _valueToBePrinted = value;
    return;
  }
  if (value == 1) {
   return value;
  }
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeksatView Question on Stackoverflow
Solution 1 - DartJohn EvansView Answer on Stackoverflow
Solution 2 - DartGreg LoweView Answer on Stackoverflow
Solution 3 - DartsrcspiderView Answer on Stackoverflow
Solution 4 - DartCutchView Answer on Stackoverflow
Solution 5 - DartLesiakView Answer on Stackoverflow
Solution 6 - DartShojaeddinView Answer on Stackoverflow
Solution 7 - DartBIS TechView Answer on Stackoverflow
Solution 8 - DartParesh MangukiyaView Answer on Stackoverflow
Solution 9 - DartJohn WangView Answer on Stackoverflow
Solution 10 - DartMabstenView Answer on Stackoverflow
Solution 11 - DartBruno Bee NahornyView Answer on Stackoverflow