Higher-order functions can be divided into categories. This recipe will explore all their different facets. Let's get started:
- Define the playground function that will define all the other types of higher-order functions that this recipe will cover:
import 'package:introduction_to_dart/04-classes.dart';
void higherOrderFunctions() {
final names = mapping();
names.forEach(print);
sorting();
filtering();
reducing();
flattening();
}
- Create a global variable called data that contains all the content that we will manipulate.
You can create a global variable by adding it to the top of the file where you are working. In DartPad, just add it to the top of the screen, before the main method. If you are in a project, you can also add it to the top of the main.dart file.
The data in the following code block is random. You can replace this with whatever content you want:
List<Map> data = [
{'first': 'Nada', 'last': 'Mueller', 'age': 10},
{'first': 'Kurt', 'last': 'Gibbons', 'age': 9},
{'first': 'Natalya', 'last': 'Compton', 'age': 15},
{'first': 'Kaycee', 'last': 'Grant', 'age': 20},
{'first': 'Kody', 'last': 'Ali', 'age': 17},
{'first': 'Rhodri', 'last': 'Marshall', 'age': 30},
{'first': 'Kali', 'last': 'Fleming', 'age': 9},
{'first': 'Steve', 'last': 'Goulding', 'age': 32},
{'first': 'Ivie', 'last': 'Haworth', 'age': 14},
{'first': 'Anisha', 'last': 'Bourne', 'age': 40},
{'first': 'Dominique', 'last': 'Madden', 'age': 31},
{'first': 'Kornelia', 'last': 'Bass', 'age': 20},
{'first': 'Saad', 'last': 'Feeney', 'age': 2},
{'first': 'Eric', 'last': 'Lindsey', 'age': 51},
{'first': 'Anushka', 'last': 'Harding', 'age': 23},
{'first': 'Samiya', 'last': 'Allen', 'age': 18},
{'first': 'Rabia', 'last': 'Merrill', 'age': 6},
{'first': 'Safwan', 'last': 'Schaefer', 'age': 41},
{'first': 'Celeste', 'last': 'Aldred', 'age': 34},
{'first': 'Taio', 'last': 'Mathews', 'age': 17},
];
- For this example, we will use the Name class, which we implemented in a previous section of this chapter:
class Name {
final String first;
final String last;
Name(this.first, this.last);
@override
String toString() {
return '$first $last';
}
}
- The first higher-order function is map. Its purpose is taking data in one format and quickly outputting it in another format. In this example, we're going to use the map function to transform the raw Map of key-value pairs into a list of strongly typed names:
List<Name> mapping() {
// Transform the data from raw maps to a strongly typed model
final names = data.map<Name>((Map rawName) {
final first = rawName['first'];
final last = rawName['last'];
return Name(first, last);
}).toList();
return names;
}
- Now that the data is strongly typed, we can take advantage of the known schema to sort the list of names. Add the following function to use the sort function in order to alphabetize the names with just a single line of code:
void sorting() {
final names = mapping();
// Alphabetize the list by last name
names.sort((a, b) => a.last.compareTo(b.last));
print('');
print('Alphabetical List of Names');
names.forEach(print);
}
- You will often run into scenarios where you need to pull out a subset of your data. The following higher-order function will return a new list of names that only begin with the letter M:
void filtering() {
final names = mapping();
final onlyMs = names.where((name) => name.last.startsWith('M'));
print('');
print('Filters name list by M');
onlyMs.forEach(print);
}
- Reducing a list is the act of deriving a single value from the entire collection. In the following example, we're going to reduce to help calculate the average age of all the people on the list:
void reducing() {
// Merge an element of the data together
final allAges = data.map<int>((person) => person['age']);
final total = allAges.reduce((total, age) => total + age);
final average = total / allAges.length;
print('The average age is $average');
}
- The final tool solves the problem you may encounter when you have collections nested within collections and need to remove some of that nesting. This function shows how we can take a 2D matrix and flatten it into a single linear list:
void flattening() {
final matrix = [
[1, 0, 0],
[0, 0, -1],
[0, 1, 0],
];
final linear = matrix.expand<int>((row) => row);
print(linear);
}