Leksat
Leksat

Reputation: 3081

How to stop Dart's .forEach()?

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?

Upvotes: 85

Views: 82724

Answers (10)

Bruno Bee Nahorny
Bruno Bee Nahorny

Reputation: 47

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;
  }
});

Upvotes: -1

Mabsten
Mabsten

Reputation: 2008

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
  });
}

Upvotes: 0

John Wang
John Wang

Reputation: 338

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;
   } 
} 

Upvotes: 1

Cutch
Cutch

Reputation: 3575

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;
    }
  }
}

Upvotes: 16

BIS Tech
BIS Tech

Reputation: 19494

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);
  }

Upvotes: 1

Shojaeddin
Shojaeddin

Reputation: 2073

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);

Upvotes: 3

srcspider
srcspider

Reputation: 11205

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);

Upvotes: 24

Greg Lowe
Greg Lowe

Reputation: 16301

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

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

Upvotes: 51

John Evans
John Evans

Reputation: 7393

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;
  }
}

Upvotes: 120

Lesiak
Lesiak

Reputation: 26064

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

Upvotes: 5

Related Questions