Перейти к содержимому

Что делает reduce в программировании

  • автор:

Знакомство с map, filter и reduce — Python: Функции

Функции высшего порядка map , filter и reduce — это наиболее распространенные и мощные инструменты в программировании. Они позволяют работать с коллекциями данных. Эти функции упрощают и ускоряют работу с данными, позволяют писать более чистый и эффективный код.

В этом уроке мы рассмотрим подробно каждую из этих функций и научимся применять их в практических задачах.

Map

Допустим, мы хотим применить к каждому элементу списка чисел функцию или операцию. Мы можем использовать цикл for , чтобы пройтись по элементам списка и применить операции к каждому элементу.

Например, у нас есть список чисел. Мы хотим получить новый список, в котором каждый элемент будет возводиться в квадрат, а затем вычитаться десять. Мы можем решить эту задачу через цикл:

numbers = [1, 2, 3, 4, 5] new_numbers = [] for num in numbers: squared = num ** 2 subtracted = squared - 10 new_numbers.append(subtracted) print(new_numbers) # [-9, -6, -1, 6, 15] 

У такого подхода есть недостатки: код становится громоздким, трудно читаемым и поддерживаемым.

В этом случае можно воспользоваться функцией map , которая позволяет применить функцию к каждому элементу коллекции. Она вернет новый список с преобразованными значениями.

map означает «отобразить». Это название пришло из математики, где так же называется функция, которая отображает одно множество значений в другое путем преобразования всех элементов с помощью трансформации. В большинстве языков также используется это имя.

Рассмотрим реализацию функции map :

def map(func, iterable): result = [] for item in iterable: result.append(func(item)) return result 

Этот цикл похож на цикл из примера выше. Здесь мы создаем пустой список result и затем циклом проходимся по элементам переданного итерируемого объекта iterable . Для каждого элемента мы вызываем функцию func и добавляем ее результат в список result . По завершении цикла мы возвращаем список result .

Теперь попробуем применить функцию map к нашей задаче:

def process_number(num): squared = num ** 2 subtracted = squared - 10 return subtracted numbers = [1, 2, 3, 4, 5] new_numbers = map(process_number, numbers) print(new_numbers) # [-9, -6, -1, 6, 15] 

В данном примере мы сначала определили функцию process_number , которую хотим применить к каждому элементу списка. Далее передали ее со списком numbers в функцию map .

Функция map позволила нам более эффективно и лаконично обработать коллекцию данных. Она применила функцию к каждому элементу коллекции и вернула новый список с преобразованными значениями.

Далее рассмотрим функцию filter .

Filter

Часто в программировании нужно отфильтровать коллекцию данных — то есть выбрать из коллекции только те элементы, которые удовлетворяют определенным условиям.

Например, если у нас есть список чисел и мы хотим получить только те, которые больше пяти, то мы можем использовать цикл for , чтобы пройтись по элементам списка и проверить условия для каждого элемента:

numbers = [2, 7, 1, 8, 4, 5] result = [] for num in numbers: if num > 5: result.append(num) print(result) # [7, 8] 

При этом у такого подхода тоже есть свои недостатки: код становится громоздким и трудночитаемым.

В этом случае можно воспользоваться функцией filter . Она позволяет отфильтровать элементы коллекции на основе заданного условия и вернуть новую коллекцию с элементами, которые удовлетворяют этому условию. Многие языки имеют аналогичную функцию с тем же именем.

Реализация функции filter аналогична реализации функции map :

def filter(func, iterable): result = [] for item in iterable: if func(item): result.append(item) return result 

Здесь мы создаем пустой список result и затем циклом проходимся по элементам переданного итерируемого объекта iterable . Для каждого элемента мы вызываем функцию func и проверяем, удовлетворяет ли он заданному условию. Если условие выполняется, то мы добавляем элемент в список result . По завершении цикла мы возвращаем список result .

Теперь рассмотрим пример использования функции filter . Допустим, у нас есть список чисел, и мы хотим получить только те числа, которые больше пяти:

def greater_than_five(num): return num > 5 numbers = [2, 7, 1, 8, 4, 5] result = filter(greater_than_five, numbers) print(result) # [7, 8] 

Здесь мы сначала определили функцию greater_than_five , которая возвращает True , если переданный ей аргумент больше пяти. Далее передали ее со списком numbers в функцию filter .

Так функция filter упростила код и повысила его читаемость и дальнейшее сопровождение.

Теперь рассмотрим функцию reduce .

Reduce

Последняя функция из нашей тройки — reduce() (говорят «свертка»), который используется для агрегации данных. Под агрегацией понимается операция, вычисляющая значение, зависящее от всего набора данных. С помощью функции reduce можно последовательно применить операции к элементам списка, чтобы получить единственное значение. Допустим, у нас есть список чисел, и мы хотим получить их сумму. В этом случае мы можем использовать цикл for , чтобы последовательно складывать каждый элемент списка. Например:

numbers = [1, 2, 3, 4, 5] result = 0 for num in numbers: result += num print(result) # 15 

В данном примере мы объявляем переменную result и присваиваем значение 0. Затем циклом for проходим по всем элементам списка numbers . Каждый элемент списка numbers прибавляем к значению переменной result . После завершения цикла в переменной result у нас хранится сумма всех элементов списка numbers .

Теперь рассмотрим пример, когда нам нужно перемножить все элементы в списке. Мы также можем решить эту задачу через цикл:

numbers = [1, 2, 3, 4, 5] result = 1 for num in numbers: result *= num print(result) # 120 

Здесь у нас код похож на сложение всех элементов списка. Отличие — начальное значение переменной result и операция, которую мы выполняем.

Теперь улучшим код для этих двух примеров. Воспользуемся функцией reduce , которая позволяет последовательно применять операцию к элементам списка, возвращая единственное значение.

Рассмотрим реализацию функции reduce :

def reduce(func, iterable, initial): result = initial for item in iterable: result = func(result, item) return result 

В данном примере на вход функции reduce передаются три аргумента:

  • func — функция, которую мы будем применять к элементам iterable
  • iterable — итерируемый объект, элементы которого мы будем обрабатывать функцией func
  • initial — начальное значение, которое будет использоваться при первом вызове функции func

Внутри функции создаем переменную result , которой в качестве начального значения передаем значение initial . Затем циклом for проходим по всем элементам объекта iterable и каждый элемент вместе со значением result передаем в функцию func . Результат функции func записываем в переменную result . Результатом работы функции reduce будет финальное значение переменной result .

Теперь рассмотрим пример использования функции reduce , чтобы найти сумму и произведение элементов списка:

def add(x, y): return x + y def multiply(x, y): return x * y numbers = [1, 2, 3, 4, 5] result = reduce(add, numbers, 0) print(result) # 15 result = reduce(multiply, numbers, 1) print(result) # 120 

Здесь мы создали две функции add и multiply , чтобы сложить и перемножить два числа. Далее мы используем функцию reduce , чтобы получить результат применения функций add и multiply к элементам списка numbers .

При первом вызове функции reduce мы передаем начальное значение 0, а при втором вызове — значение 1. Так нам удалось сократить и сделать более читаемый код.

Map, filter и reduce против цикла for

Мы можем реализовать любую логику в цикле for , но этот инструмент не всегда удобный или понятный. Например, если нам нужно преобразовать каждый элемент списка, то использование цикла for может вызвать проблемы с читаемостью кода и его поддержкой в будущем.

В этом случае мы можем воспользоваться функцией map , которая позволяет применить функцию к каждому элементу списка и вернуть новый список с преобразованными значениями. Также для выбора элементов по определенному условию вместо цикла for можно использовать функцию filter , которая вернет элементы, удовлетворяющие заданному условию.

Если нам нужно произвести агрегацию значений списка, например, сложить или умножить все его элементы, то для этого необязательно использовать цикл for . В этом случае можно воспользоваться функцией reduce , которая последовательно применяет заданную функцию к парам элементов списка и возвращает окончательный результат.

Цикл не всегда можно заменить на функции map , filter или reduce . Но если речь идет о простых манипуляциях со списками, то использование этих функций может значительно упростить чтение, написание и понимание кода. Еще это помогает избежать ошибок в логике и сделать код более читаемым и поддерживаемым в будущем, так как каждая функция делает одну работу.

Выводы

В этом уроке мы рассмотрели три функции: map , filter и reduce . Это более простой и лаконичный способ выполнить операции, которые могут быть выполнены также с помощью цикла for .

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Функция reduce() в Python

Функция reduce() модуля functools кумулятивно применяет функцию function к элементам итерируемой iterable последовательности, сводя её к единственному значению.

Аргумент function это функция которую требуется применить к элементам последовательности. Должна принимать два аргумента, где первый аргумент — аккумулированное ранее значение, а второй аргумент следующий элемент последовательности.

Аргумент iterable представляет собой последовательность, элементы которой требуется свести к единственному значению. Если последовательность пуста и не задан аргумент initializer , то возбуждается исключение TypeError .

Например reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) вычисляет ((((1 + 2) +3) +4) +5) . Левый аргумент x — это накопленное значение, а правый аргумент y — это следующий элемент iterable .

Если присутствует необязательный initializer , он помещается перед элементами iterable в вычислении. Другими словами это базовое значение, с которого требуется начать отсчёт. Аргумент initializer , так же служит значением по умолчанию, когда iterable является пустым.

Функция reduce() эквивалентна следующему коду:

def reduce(function, iterable, initializer=None): it = iter(iterable) if initializer is None: value = next(it) else: value = initializer for element in it: value = function(value, element) return value 
Примеры использования:

Вычисление суммы всех элементов списка при помощи reduce:

>>> from functools import reduce >>> items = [10, 20, 30, 40, 50] >>> sum_all = reduce(lambda x,y: x + y, items) >>> sum_all # 150 

Вычисление наибольшего элемента в списке при помощи reduce:

>>> from functools import reduce >>> items = [1, 24, 17, 14, 9, 32, 2] >>> all_max = reduce(lambda a,b: a if (a > b) else b, items) >>> all_max # 32 
  • ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
  • Способы использования модуля functools
  • Декоратор @cached_property модуля functools
  • Функция cmp_to_key() модуля functools
  • Декоратор @cache() модуля functools, кеширующий декоратор
  • Декоратор @lru_cache() модуля functools
  • Декоратор @total_ordering модуля functools
  • Функция partial() модуля functools
  • Класс partialmethod() модуля functools
  • Функция reduce() модуля functools
  • Декоратор @singledispatch модуля functools
  • Декоратор @singledispatchmethod модуля functools
  • Декоратор @update_wrapper() модуля functools
  • Декоратор @wraps() модуля functools

Малоизвестные функции Python

В этой статье будут описаны малоизвестные, но полезные, функции Python. Многие функции из этого списка могут сильно уменьшить ваш код, оптимизировать его и сделать более читаемым.

Функция filter

Функция filter предназначена для «фильтрации» массива и может заменить цикл. Filter работает быстрее цикла, в некоторых случаях скорость работа программы увеличивается в десятки раз при использовании filter, вместо классических циклов.

Функция filter принимает на вход:

  1. Другую функцию, которая возвращает True или False
  2. Cписок, элементы которого будут подаваться на вход функции

В функции, передаваемой в filter, должно содержатся условие, которое определяет критерии для элементов нового массива. Если функция возвращает True — элемент добавляется в новый массив, если False — элемент не добавляется.

Функция filter возвращает объект класса Filter, используйте list(), чтобы переделать его в массив.

Filter поможет вам сделать код более оптимизированным и читаемым.

Например, вам дан массив a, надо все числа, которые меньше 10, записать в массив b и вывести его на экран.
Как это выглядит без использования filter:

a = [1, 10, 24, 6, 8, 19] b = [] for i in range(len(a)): if a[i] < 10: b.append(a[i]) print(b)

Если использовать filter, то это выглядит так:

a = [1, 10, 24, 6, 8, 19] b = list(filter(lambda x: x< 10, a)) print(b)

Код выглядит лаконичнее и работает быстрее.

Функция map

Функцией map, так же как и функцией filter, можно заменить циклы. Циклы работают медленнее чем map, но не каждый цикл можно заменить на map.

Функция map, принимает на вход:

  1. Функцию, которой передают каждый элемент массива
  2. Массив

Каждый элемент массива подается на вход функции. Конечный массив формируется из возвращаемых функцией значений.

Функция map позволяет сделать код красивее и ускорить его работу.

ля примера возьмем проблему, которая часто встречается у меня. Вам необходимо прочитать с клавиатуры 5 чисел, введённых через пробел и вывести их сумму на экран. Так как с клавиатуры читается строка, а не числа, необходимо их всех преобразовывать в числа.

Пример без использования map:

a = input().split(" ") b = [] for i in range(5): b.append(int(a[i])) print(b[0]+b[1]+b[2]+b[3]+b[4])

Программа с использованием map:

a = list(map(int, input().split(" "))) print(a[0]+a[1]+a[2]+a[3]+a[4])

Программа с использованием map имеет меньший размер и работает быстрее, но ее можно сделать еще более быстрой с помощью следующей функции.

Функция reduce

Функция reduce работает так же как map, но reduce возвращает лишь одно значение которое получается из последнего выполнения переданной функции. Перед использованием reduce, его необходимо импортировать из модуля functools.

Функция reduce получает на вход:

  1. Функцию, которая получает более одно значения
  2. Массив, элементы которого будут поданы на вход функции

Reduce предает на вход функции элемент массива и выход предыдущего выполнения, при первом выполнении в функцию передаются первые элементы массива.

Для примера возьмем проблему которую рассматривали в прошлый раз.

Пример без reduce:

a = list(map(int, input().split(" "))) print(a[0]+a[1]+a[2]+a[3]+a[4])

Пример с использованием reduce:

from functools import reduce def summa(a, b): return a+b print(reduce(summa, list(map(int, input().split(" ")))))

В данном случае программа стала больше и не сильно быстрее, это показывает, что необходимо анализировать насколько уместно использование таких функций. В других случаях программа будет оптимизирована и уменьшена.

Множества

Множества это тип данных который работает быстрее остальных, но не может иметь повторяющихся элементов. Для создания множества используется функция set(), которой передается строка, массив, и так далее. Множества имеют методы и новые операторы:

  1. add() - добавление элемента в множество
  2. discard() - удаление элемента из множества
  3. union() - объединяет множество, из которого вызывается функция, с тем которое передается как аргумент
  4. intersection() - находит пересечение множеств, из которого вызывается, с тем которое передается как аргумент
  5. difference() - находит все элементы которые есть в множестве, из которого вызывают функцию, но которых нет в множестве переданном как аргумент
  6. symmetric_difference() - выдает множество, которое содержит все элементы из двух множеств, за исключением их общих элементов
  7. isdisjoint() - выдает True если оба множества не имею общих элементов, и False если имеют
  8. | - то же самое, что union
  9. & - то же самое, что intersection
  10. -(минус) - то же самое, что difference
  11. ^ - то же самое, что symmetric_difference

Множества имеют обширные сферы применения, даже для исключения одинаковых элементов из массива. Множества могут помочь вам сделать свой код быстрее и добавить новые возможности.

Функции any и all

Функции any и all используются вместо операторов OR и AND. Они позволяют сократить ваш код и сделать его более читаемым, в тех случаях когда вы используете большое количество условий в своей программе.

Они оба принимают массив из условий или булевых значений как аргумент, и возвращают одно булево значение.

Any - заменяет собой оператор OR, если в аргументах есть хотя бы одно True, на выходе будет True.

All - заменяет собой оператор AND, если в аргументах будет хотя бы один False, ответ будет False.

Для примера возьмем программу, которая должна вывести "1", если есть одинаковые переменные, и "-1", если таковых нет. Потом она должна проверить равна ли первая переменная второй и вторая третей, если это так вывести "2".

Пример без any и all:

a = input() b = input() c = input() d = input() if (a == b) OR (a == c) OR (a == d) OR (b == c) OR (b == d) OR (c == d): print("1") else: print("-1") if (a==b) AND (c == d): print("2")

Пример с использованием any и all:

a = input() b = input() c = input() d = input() if any([(a == b), (a == c), (a == d), (b == c), (b == d), (c == d)]): print("1") else: print("-1") if all([(a==b), (c == d)]): print("2")

Код стал приятнее глазу и немного уменьшился, эти функции уместно использовать, если вы используете большое количество условий для одного оператор if или while.

На этом все, я надеюсь вы узнали что-то новое. Если я что-то пропустил, то пишите в комментариях, если там будет много малоизвестных фишек Python, то я выпущу вторую часть.

Как работает reduce() в JavaScript, когда его нужно применять и какие крутые вещи можно с ним делать

В этой статье вы узнаете про метод reduce() и какие клевые штуки можно вытворять с его помощью, выйдя за рамки его общеизвестного применения.

��Мой Твиттер — там много из мира фронтенда, да и вообще поговорим��. Подписывайтесь, будет интересно: ) ✈️

reduce() в JavaScript это один из краеугольных камней функционального программирования. Давайте изучим то, как он работает, когда его нужно применять и то какие крутые вещи можно с его помощью вытворять.

Простая редукция

Когда использовать: когда у вас есть массив чисел и вам надо всех их сложить.

const euros = [29.76, 41.85, 46.5];
const sum = euros.reduce((total, amount) => total + amount);
sum // 118.11
  • В этом примере reduce() принимает два параметра, total и число с которым сейчас идёт работа.
  • Метод проходится по каждому числу в массиве, как бы это было с циклом for .
  • Когда цикл только начинается, total имеет значение первого числа с начала массива (29.76), а числом в обработке становится следующее по этому же массиву число (41.85).
  • Конкретно в этом примере, нам надо прибавить настоящее число к total .
  • Такое вычисление повторяется для каждого числа в массиве и каждый раз настоящее число меняется на следующее число в массиве справа.
  • Когда уже нет чисел в массиве, метод отдаёт значение total .

ES5 версия JavaScript метода reduce

Если вы до этого никогда не использовали ES6 синтаксис , то не дайте примеру выше испугать вас. Это тоже самое, что написано ниже:

var euros = [29.76, 41.85, 46.5]; 
var sum = euros.reduce( function(total, amount) return total + amount
>);
sum // 118.11

Мы используем const вместо var и мы заменим слово function на => (стрелочная функция) после параметров, а ещё мы не будем писать слово return .

Я буду писать на ES6 синтаксисе в оставшихся примерах, так как это коротко и оставляет меньше пространства для возникновения ошибок.

Находим среднее число с JavaScript методом reduce

Тут вместо вывода суммы вам надо разделить её на длину массива перед тем, как вы вернете последнее значение.

Вы можете это сделать воспользовавшись преимуществами других аргументов доступных в reduce() . Первый из них это index . Как и с циклом for , index показывает количество раз, которое редюсер пробежался по массиву. Последний аргумент это уже сам массив.

const euros = [29.76, 41.85, 46.5];
const average = euros.reduce((total, amount, index, array) => total += amount;
if( index === array.length-1) <
return total/array.length;
>else <
return total;
>
>);
average // 39.37

Map и Filter как редюсеры

Если вы можете использовать функцию reduce , чтобы найти среднее число, то следовательно, вы можете использовать её любым образом, в принципе, каким только захотите.

Для примера, вы могли бы увеличить вдвое total или разделить на два каждое число перед тем, как сложить их вместе, ну или вы бы могли использовать if в редукторе для того, чтобы сложить числа, которые больше 10. Я считаю, что в JavaScript метод reduce даёт вам что-то вроде мини CodePen, в котором вы можете записать совершенно любую логику. Он просто пропустит её через каждое число в массиве и отдаст одно значение.

Но фишка в том, что вам не обязательно отдавать только одно значение. Вы можете заредюсить массив в новый массив.

Для примера, давайте сократим массив в другой массив, в котом каждое число будет увеличено вдвое. Для этого нам надо выставить изначальное значение для аккумулятора на пустой, уже изначальный массив.

Изначальное значение — это значение параметра total при старте функции. Вы можете выставить это значение добавив запятую, за которой следует изначальное значение внутри круглых скобок, но после фигурных скобок (выделено жирным в примере ниже).

const average = euros.reduce((total, amount, index, array) => total += amount 
return total/array.length
>, 0);

В предыдущих примерах исходным значением был ноль, поэтому я просто пропускал его. Пропуская указание изначального значения, total будет по дефолту получать значение первого числа в массиве.

Указывая исходное значение, как пустой массив, мы можем в последствии добавлять каждое значение в total . Если мы хотим с помощью reduce превратить массив значений в ещё один массив, в котором каждое значение будет умножено на два, то нам нужно добавлять amount * 2 . А затем отдавать total , когда уже не останется чисел для добавления.

const euros = [29.76, 41.85, 46.5];
const doubled = euros.reduce((total, amount) => total.push(amount * 2);
return total;
>, []);
doubled // [59.52, 83.7, 93]

Мы создали новый массив, в котом каждое число умножается на два. Мы могли бы также отфильтровать числа, которые нам не нужны, просто добавив if внутри функции.

const euro = [29.76, 41.85, 46.5];
const above30 = euro.reduce((total, amount) => if (amount > 30) total.push(amount);
>
return total;
>, []);
above30 // [ 41.85, 46.5 ]

В общем, это как методы map() и filter() , только переписанные в reduce() .

Но для этих примеров было бы разумнее использовать map или filter , так как их попросту визуально легче воспринимать. Преимущество метода reduce становится очевидным, когда вам надо сделать map и filter вместе, и при этом у вас довольно большие объемы данных для обработки.

При создании цепочки с map и filter , получается то, что вы делаете одну и ту же работу дважды. Вы отфильтровываете каждое значение и затем вы пробегаетесь с указанными параметрами функции по каждому оставшемуся из них. А с reduce вы можете отфильтровать и пробежаться по всему массиву за один подход.

Используйте map и filter , но когда вы начнете выстраивать цепочку с множеством методов, то помните, что куда быстрее с этими данными применить reduce .

Ведём учёт данных с помощью reduce

Когда использовать: когда у вас есть коллекция данных и вам надо узнать то, сколько типов каждого элемента находится в этой коллекции.

const fruitBasket = ['banana', 'cherry', 'orange', 'apple', 'cherry', 'orange', 'apple', 'banana', 'cherry', 'orange', 'fig' ];const count = fruitBasket.reduce( (tally, fruit) => tally[fruit] = (tally[fruit] || 0) + 1 ; 
return tally;
> , <>)
count //

Чтобы подсчитать количество элементов в массиве, изначальным значением должен быть пустой объект, а не массив, как было в предыдущем примере.

Так как мы собираемся возвращать объект, то мы теперь можем хранить пару ключ-значение в total .

fruitBasket.reduce( (tally, fruit) => tally[fruit] = 1; 
return tally;
>, <>)

Сначала нам надо выдать имя первому ключу, назвав его как наше первое значение и затем дать ему значение 1 .

Это даст нам объект, где все названия фруктов будут в виде ключей и каждый будет иметь значение 1 . А нам нужно увеличить значение каждого фрукта, если он повторяется.

Для этого, на втором цикле мы проверяем есть ли в total ключ с данным фруктом. Если нет, то мы создаем данный ключ. А если есть, то мы увеличиваем его значение на единицу.

fruitBasket.reduce((tally, fruit) => if (!tally[fruit]) tally[fruit] = 1; 
> else tally[fruit] = tally[fruit] + 1;
>
return tally;
>, <>);

Я описал такую же логику, но более сжатым способом, который вы видели немного выше.

Сливаем массив воедино с помощью reduce

Мы можем использовать reduce , чтобы сливать воедино вложенные значения, которые в конечном итоге обретут форму единого массива.

Мы выставляем изначальное значение на пустой массив и далее конкатенируем данное значение с total .

const data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const flat = data.reduce((total, amount) => return total.concat(amount);
>, []);
flat // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Куда чаще информация вложена более сложными способами. Для примера, давайте представим, что нам надо просто получить все цвета в переменной data , находящейся ниже.

const data = [ 
,
,

];

Мы пройдемся по каждому объекту и возьмём оттуда нужные цвета. Это мы сделаем, просто указав forEach пробежаться по amount.c , где при каждой итерации, вложенный массив будет добавляться в total .

const colors = data.reduce((total, amount) => amount.c.forEach( color => total.push(color); 
>)
return total;
>, [])
Цвета
//['blue','green','green','black','orange','blue','green','red']

Если нам понадобятся только уникальные значения, то тогда нам надо будет проверить есть ли заданное значение в total , прежде чем отправлять его в этот массив.

const uniqueColors = data.reduce((total, amount) => amount.c.forEach( color => if (total.indexOf(color) === -1) total.push(color); 
>
>);
return total;
>, []);
uniqueColors // [ 'blue', 'red', 'green', 'black', 'orange']

Пайплайн с reduce()

Довольно интересным моментом в методе reduce() является то, что вы можете можете работать с функциями, как с числами и строками.

Предположим, что у нас есть набор простых математических функций, с помощью которых мы можем прибавлять, убавлять, умножать на два и делить на два значение amount .

function increment(input) function decrement(input) function double(input) function halve(input) < return input / 2; >

В общем, дальше нам надо будет увеличить значение на 1 , потом умножить на два, потом вычесть единицу.

Конечно, мы бы могли написать функцию, которая берёт input и возвращает (input + 1) * 2 -1 . Но тут проблема в том, что мы знаем то, что собираемся увеличить значение, потом удвоить его и потом вычесть единицу и затем разделить его на два, в какой-нибудь момент в будущем. Мы не хотим переписывать нашу функцию каждый раз, так что мы сделаем пайплайн с помощью reduce() .

Пайплайн (pipeline) это термин, который используется для набора функций, которые последовательно изменяют какое-либо значение в уже финальный результат. Наш пайплайн будет состоять из трех функций, в том порядке, в котором мы хотим их использовать.

let pipeline = [increment, double, decrement];

В общем, теперь мы используем reduce() не на массиве значений, а на пайплайне из функций. Такая конструкция сработает, потому что мы выставили изначальное значение на то, которое хотим в дальнейшем трансформировать.

const result = pipeline.reduce(function(total, func) return func(total);
>, 1);
result // 3

Так как пайплайн у нас является массивом, то он может быть легко модифицирован. Если мы хотим что-нибудь увеличить на 1 три раза подряд, потом вдвое увеличить, вычесть 1 и разделить на два, то нам будет достаточно просто изменить пайплайн.

var pipeline = [ 
increment,
increment,
increment,
double,
decrement,
halve
];

Сама функция останется такой же.

Избегаем глупых ошибок

Если вы не передадите изначальное значение, то reduce() будет считать, что им является первый элемент в массиве. Всё работало отлично в первых примерах, потому что мы работали со списком чисел.

Если вы захотите подсчитать фрукты и упустите изначальное значение, то ничего у вас тогда не выйдет. Вообще, упущение момента указания изначального значения это ошибка, которую легко пропустить и именно её нужно проверять первым делом при дебаггинге.

Ещё частенько забывают отдавать total . Вы должны возвращать какое-нибудь значение, что reduce() продолжал работать. Всегда проверяйте дважды и убеждайтесь в том, что вы отдаёте нужное вам значение.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *