Conceptual Understanding
These methods are a lot easier to digest and understand when we look at it through a more simplistic lens. In their essence, the methods are an extension of the same principles and ideas behind ‘forEach’ loops.
These methods accept a set of data and a condition, and returns to us a new piece of information or a set of data that adheres to the given condition. And by this very definition, we can understand that these are all non-void functions, which mean two things, one, their products can be assigned to a variable, and two, they do not modify the original collection.
Now, let’s take a look at them individually.
where()
The HashSet<E>
class provides the where()
method, which returns all the elements of the HashSet that satisfy the specified input condition.
HashSet<E>
is a collection of unique elements that provide constant-timeadd
,remove
, andcontains
operations.HashSet<E>
does not have a specified iteration order. However, multiple iterations on the set produce the same element order.
The where() method is conventionally named “filter()” in other languages out there, such as Java and Javascript. It accepts a collection of items and a condition, filters the collection based on the condition and returns a new collection of filtered items.
The where() method accepts a collection of various items and returns us specific items, in this case a collection of cheese items, omitting other items. The condition supplied to it has to specify what it needs to filter out.
The where() method’s number of items returned depends on the condition.
The where() method always returns a collection. If the provided condition does not have any matching items, it still returns an empty collection. This makes it null-safe.
You can use where in list, set, map to filter specific items. It returns a new list containing all the elements that satisfy the condition. This is also called Where Filter in dart. Let’s see the syntax below:
Syntax
Iterable<E> where(
bool test(
E element
)
)
Example 1: Filter Only Odd Number From List
In this example, you will get only odd numbers from a list.
void main() {
List<int> numbers = [2, 4, 6, 8, 10, 11, 12, 13, 14];
List<int> oddNumbers = numbers.where((number) => number.isOdd).toList();
print(oddNumbers);
}
[11, 13]
Example 2: Filter Days Start With S
In this example, you will get only days that start with alphabet s.
void main() {
List<String> days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
];
List<String> startWithS =
days.where((element) => element.startsWith("S")).toList();
print(startWithS);
}
[Sunday, Saturday]
Example 3: Where Filter In Map
In this example, you will get students whose marks are greater or equal to 32.
void main() {
Map<String, double> mathMarks = {
"ram": 30,
"mark": 32,
"harry": 88,
"raj": 69,
"john": 15,
};
mathMarks.removeWhere((key, value) => value < 32);
print(mathMarks);
}
{mark: 32.0, harry: 88.0, raj: 69.0}
reduce()
The reduce() method operates in a slightly different way, it is an accumulator function.
The method operates by comparing the current value against the preceding value based on the condition it was supplied with. Thus, it always operates with two values at any given moment in time, starting with indexes 0 and 1 in a collection.
It returns us back a single value that satisfies the condition given to it instead of a collection. This value can be a standalone one from that collection, or a synthesised value of all the values within the collection.
Let’s try to make sense of all these technical mumbo jumbo through some illustrations.
In the above illustration, we can see the reduce() being used to determine the smallest piece of cheese in the collection. It compares the first two cheeses and retains the smallest value between them, carrying it forward. This repetition happens till the end of the collection, determining the smallest cheese.
Finally, we can observe the reduce() being used to manufacture a large piece of cheese. It melts all the small pieces of cheese to make a large piece of cheese. This is an example of a synthesised result from a collection of items.
As you can see, in all three examples, it returns a single value.
Examples
In the following program, we take a Set mySet
, with some numbers, and reduce these numbers to their sum.
main.dart
int sum(int s, int e) { return s + e; } void main() { Set<int> mySet = {1, 3, 6, 10, 13, 15, 20}; var result = mySet.reduce(sum); print('Result : $result'); }
Output
Result : 68
Now, let us take the same Set as in the above example, but reduce the elements to their product.
main.dart
int product(int s, int e) { return s * e; } void main() { Set<int> mySet = {1, 3, 6, 10, 13, 15, 20}; var result = mySet.reduce(product); print('Result : $result'); }
Output
Result : 702000
Conclusion
Now that we’ve arrived at the end of this article, these are the takeaways from it:
- map(), where() and reduce() make it easier for perform operations on collections
- map() is a sort of transformer method that accepts n number of items, modifies it, and gives us back n number of items.
- where() filters out whatever we need from a collection and gives us back a new collection.
- reduce() gives us back an accumulation from the collection based on the condition, may it summation, minimum or even maximum, but it will always be a single value.
- We can chain map(), where() and reduce() together to achieve specific goals.
- Using these methods ensures immutability as it returns a value and can be assigned directly to a variable without the need to modify the original collection.
- Approaches using map(), where() and reduce() promotes declarative programming.
- They improve testability greatly by encapsulating logical flow in a proper sequence and can be unit tested directly.