Потому что этот молоток на самом деле является швейцарским армейским ножом!

Когда я впервые столкнулся с функцией reduce в Javascript, мне показалось странным ее использование. У меня был код с различными массивами повсюду, но прямо здесь мне нужно было создать объект, а не массив. Это означало, что я не мог использовать методы forEach и map, к которым я привык - вместо этого мне пришлось использовать reduce.

Итак, во-первых, это было странно, потому что он принимал массив и выдавал объект. Мне казалось, что я перемещаюсь из одного мира в другой. И в дополнение к этому вы добавляете для передачи эту странную «аккумуляторную» переменную.

Вряд ли я знал, что на самом деле я только что наткнулся на удивительный инструмент ... :)

Использование reduce: основы

Основная идея функции reduce состоит в том, чтобы перебирать список значений и использовать их для постепенного «заполнения аккумулятора». Этот аккумулятор представляет собой переменную любого типа, которую вы хотите, которую вы просто инициализируете в самом начале сокращения, а затем изменяете (или просто пропускаете) на каждой итерации. Обычное использование reduce - это вариант использования, о котором я говорил во вступлении: создание объекта из массива вещей.

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

{
  id: '20210512-my-first-article',
  title: 'My first article',
  pubdate: '2021-05-12T14:20:19.528622',
  excerpt: 'This is my first article - yay!',
  // ... additional info
}

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

Таким образом, более чем вероятно, что на веб-сайте есть какая-то логика, в которой он считывает идентификатор в URL-адресе и использует его для получения информации и содержания сообщения в блоге. Это означает, что вам нужно найти нужный объект в массиве сообщений вашего блога.

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

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

Вот небольшой пример JS-скрипта, который создает массивы сообщений в блогах различного размера, а затем использует метод find для получения сообщения с наибольшим идентификатором (то есть последнего элемента в списке):

Если мы запустим его, мы получим те результаты, которые ясно показывают, как размер коллекции влияет на время вычислений:

n = 10
Compute time: 0.078ms
n = 100
Compute time: 0.008ms
n = 1000000
Compute time: 14.524ms
n = 10000000
Compute time: 140.235ms

Общее практическое правило для времени отклика API - держать его меньше 1 секунды, иначе пользователь заметит задержку (и помните, что здесь мы уже ждали, чтобы дождаться страницы статьи - теперь мы на странице мы ожидаем, что он будет загружен мгновенно). Итак, очевидно, что наша программа не прошла бы мимо, если бы у нас были десятки миллионов статей… (конечно, это большое количество статей, но, эй, вы должны быть готовы ко всему!).

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

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

И все это для того, чтобы, наконец, представить наш reduce пример! Очень распространенный метод решения этой проблемы «перестройки структуры данных» - сохранить «объектную версию» сообщений вашего блога в коде веб-сайта, чтобы всякий раз, когда вам нужно получить доступ к статье по ее идентификатору, вы могли очень быстро получить ее в этом оптимизированное отображение.

Функция reduce требует, чтобы вы определили 3 вещи:

  • массив, который вы повторяете
  • функция, применяемая на каждой итерации: она принимает как ваш аккумулятор, так и текущий элемент в вашей повторяющейся коллекции
  • начальное значение для аккумулятора

Вот пример того, как преобразовать массив сообщений нашего блога в объект, используя идентификатор статьи в качестве ключа:

Первоначальное преобразование может быть долгим, но как только оно будет выполнено, вы получите доступ ко всему в мгновение ока!

Примечание: область алгоритмики изучает, помимо прочего, структуры данных и связанную с ними сложность для различных операций. Здесь мы говорим о доступе к определенному элементу в структуре. С массивом и его методом find эта операция считается (наихудший сценарий) за O (n), что означает, что она растет линейно с количеством элементов в списке - если у вас вдвое больше элементов и ваш статья является последней, вам придется пройти в два раза больше проверок, прежде чем вы ее доберетесь. С другой стороны, прямое отображение объекта находится в O (1), то есть доступ занимает постоянное время и не зависит от количества элементов.

Использование reduce для вычисления суммы, среднего ...

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

Примечание: я кратко упомянул задачи CodinGame в предыдущем Quickie Dev, но вы, вероятно, увидите, насколько это может быть полезно для решения некоторых из их головоломок при работе с Javascript! ;)

Однако я должен отметить, что reduce, хотя и очень легко читается, не обязательно является наиболее эффективным вариантом для вычисления сумм, средних и т. Д. Простой цикл for может быть намного лучше.

Использование reduce для фильтрации

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

Например, предположим, что у вас есть список чисел, и вас интересует только квадрат четных. Вы можете сначала применить filter, а затем map, но для этого потребуется n + t операций (где n - начальное количество элементов, а t - количество отфильтрованных элементов).

С помощью reduce вы уменьшаете количество операций до n, поскольку выполняете все сразу:

Заключение

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

А вы? У вас есть советы и рекомендации по использованию reduce Javascript? Не стесняйтесь реагировать в комментариях! :)

Если вам понравилась эта статья, вы можете найти больше сообщений в блоге о технологиях, искусственном интеллекте и программировании на моем сайте :)