Dart Tutorial

Dart Lesson 33 of 102 3 min read

where, map, reduce and fold in Dart: Filter and Transform Collections

Filter, transform and summarise collections in Dart with where, map, expand, reduce, fold, any and every, with practical examples.

On this page

Most loops do one of three things: pick some items, change every item, or boil everything down to one value. Dart has a method for each, and using them makes the intent of your code obvious.

where: keep the items that pass a test #

void main() {
  var ages = [12, 25, 17, 40, 8, 33];

  var adults = ages.where((age) => age >= 18).toList();
  print(adults);
}
[25, 40, 33]

The function you pass is called once per item and returns true to keep it. where never changes the original list.

Two useful relatives:

void main() {
  var mixed = [1, 'two', 3, null, 'five'];

  print(mixed.whereType<int>().toList());     // only the ints
  print(mixed.nonNulls.toList());             // drop the nulls
}
[1, 3]
[1, two, 3, five]

map: transform every item #

void main() {
  var names = ['asha', 'bimal', 'chandra'];

  var capitalised = names
      .map((n) => n[0].toUpperCase() + n.substring(1))
      .toList();
  var lengths = names.map((n) => n.length).toList();

  print(capitalised);
  print(lengths);
}
[Asha, Bimal, Chandra]
[4, 5, 7]

The result has the same number of items, and they can be a different type.

expand: one item becomes many #

void main() {
  var orders = [
    ['tea', 'toast'],
    ['coffee'],
    ['juice', 'eggs', 'toast'],
  ];

  var allItems = orders.expand((order) => order).toList();
  print(allItems);
}
[tea, toast, coffee, juice, eggs, toast]

reduce: combine into one value of the same type #

void main() {
  var prices = [250, 120, 480, 90];

  var total = prices.reduce((sum, p) => sum + p);
  var cheapest = prices.reduce((a, b) => a < b ? a : b);

  print(total);
  print(cheapest);
}
940
90

reduce throws an error on an empty collection, because there is nothing to start from.

fold: combine with a starting value #

fold is the safer, more flexible version. You give it a starting value, and the result can be a different type from the items.

void main() {
  var words = ['dart', 'is', 'fun'];

  var letters = words.fold(0, (count, w) => count + w.length);
  var sentence = words.fold('', (text, w) => text.isEmpty ? w : '$text $w');
  var emptyTotal = <int>[].fold(0, (a, b) => a + b);

  print(letters);
  print(sentence);
  print(emptyTotal);
}
9
dart is fun
0

any and every #

void main() {
  var marks = [55, 72, 38, 90];

  print(marks.any((m) => m < 40));   // did anyone fail?
  print(marks.every((m) => m >= 30)); // is everyone at least 30?
}
true
true

Putting them together #

void main() {
  var products = [
    {'name': 'Pen', 'price': 20, 'inStock': true},
    {'name': 'Bag', 'price': 1500, 'inStock': false},
    {'name': 'Book', 'price': 350, 'inStock': true},
    {'name': 'Lamp', 'price': 900, 'inStock': true},
  ];

  var available = products.where((p) => p['inStock'] == true);
  var names = available.map((p) => p['name']).join(', ');
  var value = available.fold(0, (sum, p) => sum + (p['price'] as int));

  print('Available: $names');
  print('Total value: $value');
}
Available: Pen, Book, Lamp
Total value: 1270

Quick reference #

MethodGives backUse it to
whereFewer itemsFilter
mapSame count, changed itemsTransform
expandMore itemsFlatten
reduceOne value, same typeTotal, min, max
foldOne value, any typeTotal with a start value
any / everyboolCheck a condition

Try it yourself #

From [3, 8, 15, 22, 7, 10], keep the even numbers, square them, and add them up, all in one chain. The answer is 648.

Practise in the playground Updated by Santosh Adhikari