JavaScript: Использование Map, Filter, и Reduce вместе
Это заключительная статья мини курса по обработки данных в JavaScript. Где мы научимся создавать цепочку вызовов всех изученых ранее методов, для получения более комплексных и интересных манипуляций с данными.
Содержимое мини-курса:
- Функция Map()
- Функция Filter()
- Функция Reduce()
- Выполнение цепочки, Map(), Filter(), Reduce() вместе
Вы здесь
Рассмотрим следующие данные:
data = [
{
name: 'Butters',
age: 3,
type: 'dog'
},
{
name: 'Lizzy',
age: 6,
type: 'dog'
},
{
name: 'Red',
age: 1,
type: 'cat'
},
{
name: 'Joey',
age: 3,
type: 'dog'
},
];
Давайте представим, что у нас есть коллекция объектов. Каждый объект представляет собой домашнее животное. У домашних животных есть имя, возраст и тип.
Нашей целью будет написать код, который суммирует возраст всех собак и переводит их в человеческий возраст. Процесс будет выглядеть следующим образом:
- Выбираем из коллекции только собак
- Переводим возраст на человеческий манер (умножаем на семь)
- Суммируем результаты
По традиции показываю как бы мы это делали ранее, до прохождения нашего миникурса используя цикл for:
function getAges(data) {
let sum = 0;
for (var i = 0; i < data.length; i++){
if (data[i].type === 'dog'){
let tempAge = data[i].age;
sum += (tempAge * 7);
}
}
return sum;
}
// getAges(data) = 84
Сначала мы создали переменную sum
и задали ей значение равное 0. Затем перебираем наш массив, по одному объекту за раз. Если на данной итерации питомец — собака, берем возраст этой собаки, умножаем ее на семь и добавляем полученное значение к нашей сумме. Повторяем эту операцию для каждой собаки в массиве. Когда наша цикл заканчивается, возвращаем сумму.
В результате отработки этого кода мы молучаем sum = 84
. Этот код работает но как вы наверное уже догадались, эту задачу можно решить более элегантным способом.
Давайте теперь решим эту-же задачу используя функции map()
, reduce()
и filter()
. Для налача давайте отфильтруем наши данные по типу животного, где нас интересуют собаки:
let ages = data.filter((animal) => {
return animal.type === 'dog';
})
После того как мы получили коллекцию с типом интересующих нас данных, будем искать возраст собак и умножать каждый на 7. Сделаем это с помощью функции map()
. Наша функция map()
просто вернет возраст животных, умноженный на 7.
.map((animal) => {
return animal.age *= 7
})
Ну и наконец нам нужно сложить возраст всех собак, в этом нам поможет метод Reduce()
.reduce((sum, animal) => {
return sum + animal.age;
});
Таким образом, когда все три этапа завершены, мы просто объединяем предыдущие действия. Вот как будет выглядеть наш код:
let ages = data
.filter((animal) => {
return animal.type === 'dog';
}).map((animal) => {
return animal.age * 7
}).reduce((sum, animal) => {
return sum + animal.age;
});
// ages = 84
Как и ожидалось, результатом выполнения будет 84 в переменной ages. Но наш код всё ещё трудно читаемый. Что бы исправить это, давайте создатим три чистые функции и будем вызывать их по цепочке.
Чистые функции — это любые функции, исходные данные которых получены исключительно из их входных данных и не влияют на работу остального приложения. Самый простой пример: это функция которая принимает на входе два числа, и на выходе возвращает их сумму
Дл начала давайте создадим функцию, которая проверяет, является ли переданный елемент собакой, и возвращает на выходе либо true
либо false
let isDog = (animal) => {
return animal.type === 'dog';
}
Затем создадим функцию которая умножает на 7 свойство возраст из переданного элемента и возвражает возраст измеряемый в собачьих годах
let dogYears = (animal) => {
return animal.age * 7;
}
И теперь нам нужна функция которая будет складывать оба результата из предыдущих функций и возвращать нам значение
let sum = (sum, animal) => {
return sum + animal;
}
Теперь когда у нас есть все три функции мы можем выполнить их как цепочку
let ages = data
.filter(isDog)
.map(dogYears)
.reduce(sum);
// ages = 84
Такой подход в организации кода гораздо проще для чтения и понимания. На выходе мы получаем чистые функции и возможность переиспользования логических блоков кода по мере необходимости.