How to stop Dart's .forEach()? - dart

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?

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

It is also possible to implement your example using forEach() and takeWhile().
var data = [1, 2, 3];
data.takeWhile((val) => val != 2).forEach(print);

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

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

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

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

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

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

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

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

Related

Why is my binary search implementation returning -1?

This is my main.dart:
import 'edgecases.dart';
main () {
var card = edgecases(0)['input']['cards'];
var query = edgecases(0)['input']['query'];
var result = locate_card(edgecases(0)['input']['cards'], edgecases(0)['input']['query']);
var output = edgecases(0)['output'];
print("Cards:- $card");
print("Query:- $query");
print("Output:- $result");
print("Actual answer:- $output");
}
And this is my edgecases.dart:
edgecases ([edgecasenumber = null]) { //You may make it required, I provided a null as default to check if my syntax is going right.
List tests = [];
var edge1 = {'input': {
'cards': [13, 11, 10, 7, 4, 3, 1, 0],
'query': 1
}, 'output': 6};
tests.addAll([edge1]);
if (edgecasenumber == null){ // This if is useless here so you may
return 'Null type object coud not be found.';
} else {
return tests.elementAt(edgecasenumber); // Indexing in dart also starts with 0.
}
}
locate_card (List cards, int query){
int lo = 0;
int hi = cards.length - 1;
print('$lo $hi');
while (lo <= hi) {
//print('hello'); Uncomment to see if it is entering the loop
var mid = (lo + hi) ~/ 2;
var mid_number = cards[mid];
print("lo:$lo ,hi:$hi, mid:$mid, mid_number:$mid_number");
if (mid_number == query){
return mid;
} else if (mid_number < query) {
hi = mid - 1;
} else if (mid_number > query) {
lo = mid + 1;
};
return -1; //taking about this line
};
}
[I have cut short the code here so you may find some things as unnecessary so just ignore it XD]
Actually I am trying to implement binary search here(I have previously successfully implemented it in python, I am implementing in dart to learn the language.)
On testing it with first edge case(that is on running the command dart main.dart), I found that it is returning the value -1 which was wrong, so I tried commenting the return -1; line in edgecases.dart file to see what happens as it was made to handle another edge case(edgecase if the list is empty, here I have removed that for simplicity). I am not able to understand why it is returning -1 if it gives the right value on commenting that line. Any possible explainations and solutions?
Thanks in advance!
You almost did it right. Just place the return -1; after the while loop's closing brace at the very end of locate_card.

How to slice a list with a custom step/increment in Dart?

In Python, you can specify a "step" argument to a list slice that specifies the separation between indices that are selected to be in the slice:
my_list[start:stop:step]
However, none of the list methods in Dart seem to offer this functionality: sublist and getRange just take the start and end index.
How can I do this in Dart without using an ugly for-loop?
For example, to select only the even indices of a list I currently see no alternative to this:
List<Object> myList = ...;
List<Object> slice = [];
for (var i = 0; i < myList.length; i += 2) {
slice.add(myList[i]);
}
Or slightly less ugly with a list comprehension:
[for (var i = 0; i < myList.length; i += 2) myList[i]]
I could write my own function or extension method, but that defeats the purpose, I'm looking for ideally a built-in or a third package solution.
For this you can create extension on list to return custom result.
List<T> slice([int? start, int? end, int? step]) {
if (start == null && end == null && step == null) {
return this!;
} else if (start != null && end == null && step == null) {
return this!.sublist(start);
} else if (start != null && end != null && step == null) {
return this!.sublist(start, end);
} else if (start != null && end != null && step != null) {
// iterate over the list and return the list
// iterator start from start index
// iterator end at end index
// iterator step by step
final list = <T>[];
for (var i = start; i < end; i += step) {
list.add(this![i]);
}
return list;
} else {
return this!;
}
}
You can use the slice extension on any list. Below are examples of how to use it.
Example 1
This example will return the slice list of the list depending starting and ending index.
final list1 = [1, 2, 3, 4, 5];
final result = list1.slice(1, 4);
print(result); // [2, 3, 4]
Example 2
This example will return the slice list of the list depending starting index.
final list1 = [1, 2, 3, 4, 5];
final result = list1.slice(1);
print(result); // [2, 3, 4, 5]
Complate program.
You can run this example in Dartpad to check results.
void main() {
final list1 = [1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15,15,17,18,19,20];
// Example - 1
final result = list1.slice(1, 4);
print(result); // [2, 3, 4]
//Example - 2
final result2 = list1.slice(10);
print(result2); // [11, 12, 13, 14, 15, 15, 17, 18, 19, 20]
//Example - 3
final result4 = list1.slice(4, 10, 2);
print(result4); // [5, 7, 9]
//Example - 4
final result3 = list1.slice();
print(result3); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 17, 18, 19, 20]
}
extension ListHelper<T> on List<T>? {
List<T> slice([int? start, int? end, int? step]) {
if (start == null && end == null && step == null) {
return this!;
} else if (start != null && end == null && step == null) {
return this!.sublist(start);
} else if (start != null && end != null && step == null) {
return this!.sublist(start, end);
} else if (start != null && end != null && step != null) {
// iterate over the list and return the list
// iterator start from start index
// iterator end at end index
// iterator step by step
final list = <T>[];
for (var i = start; i < end; i += step) {
list.add(this![i]);
}
return list;
} else {
return this!;
}
}
}
You can easily create your own slice method in Dart.
The first thing to decide is whether you want it to be lazy or eager—does it create a list or an iterable.
The traditional Dart way would be an iterable, created from another iterable, which is also slightly more complicated to write.
extension LazySlice<T> on Iterable<T> {
/// A sub-sequence ("slice") of the elements of this iterable.
///
/// The elements of this iterable starting at the [start]th
/// element, and ending before the [end]th element, or sooner
/// if this iterable has fewer than [end] elements.
/// If [end] is omitted, the sequence continues
/// to the end of this iterable.
/// If [step] is provided, only each [step]th element of the
/// [start]..[end] range is included, starting with the first,
/// and skipping `step - 1` elements after each that is included.
Iterable<T> slice([int start = 0, int? end, int step = 1]) {
// Check inputs.
RangeError.checkNotNegative(start, "start");
if (end != null && end < start) {
throw RangeError.range(end, start, null, "end");
}
if (step < 1) {
throw RangeError.range(step, 1, null, "step");
}
// Then return an iterable.
var iterable = this;
if (end != null) iterable = iterable.take(end);
if (start > 0) iterable = iterable.skip(start);
if (step != 1) iterable = iterable.step(step);
return iterable;
} // slice
/// Every [step] element.
///
/// The first element of this iterable, and then every
/// [step]th element after that (skipping `step - 1`
/// elements of this iterable between each element of
/// the returned iterable).
Iterable<T> step(int step) {
if (step == 1) return this;
if (step < 1) {
throw RangeError.range(step, 1, null, "step");
}
return _step(step);
}
/// [step] without parameter checking.
Iterable<T> _step(int step) sync* {
var it = iterator;
if (!it.moveNext()) return;
while (true) {
yield it.current;
for (var i = 0; i < step; i++) {
if (!it.moveNext()) return;
}
}
} // _step
} // extension LazySLice
Working with a list is much easier:
extension EagerSlice<T> on List<T> {
List<T> slice([int start = 0, int? end, int step = 1]) {
if (step == 1) return sublist(start, end); // Checks parameters.
end = RangeError.checkValidRange(start, end, length);
if (step < 1) {
throw RangeError.range(step, 1, null, "step");
}
return <T>[for (var i = start; i < end; i += step) this[i]];
}
}
(Effectively the same approach proposed by #Anakhand in the comments above, just with better parameter checking.)
The list approach is easier, mainly because we don't already have a step method on iterables, which picks every nth element.

Check if element is the last value in fold function

I am using fold on an array which hasn't been assign to a variable and want to check whether the element is the last value. With a conventional for loop I can do this:
List<int> ints = [1, 2, 3];
int sum = 0;
for (int num in ints]) {
if (num != ints.last) {
sum = sum + num;
}
}
print(sum);
Is it possible to do this with fold instead?
int foldSum = [1, 2, 3].fold(0, (int prev, element) => prev + element);
print(foldSum);
I can't find any way of check when fold is at the last value. Note: this is a simplified example of my problem and the reason the list isn't assigned to a variable (allowing me to use .last) is because it is the result of a call to .map().
For completeness, below is the actual code (which won't obviously won't be runnable in isolation but will help illustrate my problem) I am trying to convert to use .map and .fold:
String get fieldsToSqlInsert {
String val = "";
for (Column column in columns) {
if (data.containsKey(column.name)) {
val = '$val "${data[column.name]}"';
} else {
val = "$val NULL";
}
if (column != columns.last) {
val = "$val,";
}
}
return val;
}
But it doesn't work because I don't know how to check when fold is at the final element:
String get fieldsToSqlInsert => columns
.map((column) =>
data.containsKey(column.name) ? data[column.name] : "NULL")
.fold("", (val, column) => column != columns.last ? "$val," : val);
If you simply want to exclude the last element from further calculation, you can just use take to do so:
String get fieldsToSqlInsert => columns.take(columns.length - 1)...

How to find all subsets of a set in Dart?

I need to get all possible subsets of an array.
Say I have this:
<int>[1, 2, 3]
How do I get this?
[], [1], [2], [3],[1, 2], [2, 3], [1, 3], [1, 2, 3]
I am interested in all subsets. For subsets of specific length, refer to the following questions:
How to find all subsets of a set in JavaScript?
Here is my take on it, with only native function as in your link:
List getAllSubsets(List l) => l.fold<List>([[]], (subLists, element) {
return subLists
.map((subList) => [
subList,
subList + [element]
])
.expand((element) => element)
.toList();
});
If you want a specific size:
List getSizedSubsets(List l, int size) =>
getAllSubsets(l).where((element) => element.length == size).toList();
I'd probably go with something simple like:
Iterable<Set<E>> subsets<E>(Set<E> elements) sync* {
if (elements.length >= 32) {
// Otherwise there'll be more than 2^32 subsets. And bitops will overflow in JS.
throw ArgumentError.value(elements, "elements", "must have less than 32 elements");
}
var list = [...elements];
var subsetCount = 1 << list.length;
for (var i = 0; i < subsetCount; i++) {
yield {
for (var j = 0, bit = 1; j < elements.length; j++, bit <<= 1)
if (i & bit != 0) list[j]
};
}
}
Another approach is to only have one set, and then update it iteratively to contain different elements. It's possible to go through all the sets doing only single-element changes on each step (using Gray-code):
/// Iterates a set through all combinations of its elements.
///
/// Adds and removes elements from [set] to make it iterate through all
/// possible combinations of its initial elements.
/// The current value of the iterator is always [set].
/// If iterated through to the end, the [set] ends up with all its original elements.
Iterable<Set<E>> subsets<E>(Set<E> set) sync* {
if (set.length >= 32) {
throw ArgumentError.value(set, "set", "must have less than 32 elements");
}
var list = [...set];
var prev = 0;
var counter = 0;
do {
yield set;
var next = ++counter ^ (counter >> 1);
var bit = prev ^ next; // One bit set.
var index = bit.bitLength - 1;
if (index >= list.length) index = 0;
var element = list[index];
if (next & bit == 0) {
set.add(element);
} else {
set.remove(element);
}
prev = next;
} while (set.length < list.length);
}

idiom for auto-initializing map values to 0

Is there a better idiom for auto-initializing Map values to 0 than the following? In the following code there is an asymmetry between the approach to adding a value to a target of type List versus int.
main() {
addToList(Map m, v) =>
m..putIfAbsent('foo', () => []).add(v);
///////////////////////////////////////////////////////////
// Not allowed (expression is not assignable)
// addToScalar(Map m, v) =>
// m..putIfAbsent('foo', () => 0) += 3;
addToScalar1(Map m, v) {
m.putIfAbsent('foo', () => 0);
m['foo'] += v;
return m;
}
addToScalar2(Map m, v) {
if(m.containsKey('foo')) {
m['foo'] += v;
} else {
m['foo'] = v;
}
return m;
}
print(addToList({}, 3));
print(addToScalar1({}, 3));
print(addToScalar2({}, 3));
}
Conceptually addToList and addToScalar do similar things. But the analog for the int stored as a value type might be:
m.putIfAbsent('foo', () => 0) += someValue
which will not work since what is returned from putIfAbsent is not assignable. So with both the working approaches used in the scalar case the lookup in the map for key 'foo' is being done twice. Can this be avoided with the Map API?
No, you cannot currently avoid two lookups in order to modify a map value.
We have considered, but never decided on, a way to achieve that (e.g., an "update" method).
The Two shortest/most efficient solution to your problem are:
int _returnZero() => 0; // Toplevel or static function.
...
map[key] = map.putIfAbsent(key, _returnZero) + v;
...
and:
int value = map[key];
map[key] = (value == null) ? v : value + v;

Resources