Рубрики
Без рубрики

Деконструкция карты, фильтровать и уменьшить

Мастер `map`,` filter` и «уменьшить» путем деконструкции и восстановления их с нуля. Tagged с помощью JavaScript, функциональный, уменьшить.

Сегодня мы будем освоить карта , фильтр и уменьшить деконструировав и восстанавливая их с нуля.

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

К облегчению моей матери, я смог вернуть часы обратно в его оригинальное рабочее состояние. Тщательно осмотрев внутренние, я ушел с лучшим пониманием того, что делает часы.

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

Начнем с рассмотрения уменьшить внешне. Сразу же я могу идентифицировать 4 части. массив , Метод , Reducer и ИСТИНАЛЬНАЯ ВАЛА Анкет

const items = [ 1, 2, 3, 4 ]
const initialValue = 0
const reducer = (accumulator, currentValue) => accumulator + currentValue
items.reduce(reducer, initialValue) //=> 10
/* \     \      \          \
  array   \      \           - initial value
        method    \
                reducer
*/

Все довольно самостоятельно. Все, кроме Reducer Анкет Это требует дальнейшего срыва.

Примечание: у редукторов есть 4 параметра, пока мы проигнорируем последние 2 и сосредоточимся на аккумулятор и текущая стоимость .

Эти параметры обычно сокращены как acc и cur Анкет

const reducer = (acc, cur) => acc + cur

Поскольку вы уже знакомы для петли, я могу использовать цикл для FOR ниже, чтобы помочь продемонстрировать, что аккумулятор и CurrentValue есть и как они используются.

const items = [ 1, 2, 3, 4 ]
let acc = 0
//         \
//       initial value
for (let i = 0; i < items.length; i++) {
  const cur = items[i]
//        \
//     current value
  acc = acc + cur
//     \
//   update the accumulator
}

И вставить Reducer

for (let i = 0; i < items.length; i++) {
  const cur = items[i]
  acc = reducer(acc, cur)
}

Если вы хотите увидеть больше подобных сбоев, ознакомьтесь с картой, фильтрованием, уменьшите VS для петли (синтаксис).

В примере выше, Аккумулятор это Номер , но это не должно быть Номер , это может быть любой тип.

В этом примере acc это Массив и Reducer выдвигает удвоенное значение в аккумулятор .

const items = [ 1, 2, 3, 4 ]

const reducer = (acc, cur) => {
  acc.push(cur * 2)
  return acc
/*         \
   The reducer must always return the accumulator
*/       
}

let acc = []

for (let i = 0; i < items.length; i++) {
  const cur = items[i]
  acc = reducer(acc, cur)
}

acc //=> [ 2, 4, 6, 8 ]

В этом примере Аккумулятор является объектом, а новые значения добавляются в объект.

const items = [ 1, 2, 3, 4 ]

const reducer = (acc, cur) => {
  acc[cur] = cur * 2
  return acc
}

let acc = {}

for (let i = 0; i < items.length; i++) {
  const cur = items[i]
  acc = reducer(acc, cur)
}

acc //=> { 1:2, 2:4, 3:6, 4:8 }

Вы должны заметить между этими примерами, код цикла был идентичен. Не верите мне? Давай прокрутите обратно и проверьте! Только ИСТИНАЛЬНАЯ ВАЛА и Reducer измененный. Итак, будь то Аккумулятор это Номер , а Массив , а Объект , или какой -то другой тип … Вам нужно только изменить Начальное значение и Reducer , не петля!

Поскольку мы знаем, что для цикла никогда не меняется, это легко извлечь его в собственную функцию, уменьшить Анкет

const reduce = () => {
  for (let i = 0; i < items.length; i++) {
    const cur = items[i]
    acc = reducer(acc, cur)
  }
}

Ваш Линтер должен жаловаться на отсутствие Reducer и Предметы Итак, давайте добавим их. Мы также добавим ИСТИНАЛЬНАЯ ВАЛА Пока мы в этом.

const reduce = (items, reducer, initialValue) => {
  let acc = initialValue
  for (let i = 0; i < items.length; i++) {
    const cur = items[i]
    acc = reducer(acc, cur)
  }
  return acc
}

Это оно? Мы только что создали уменьшить ? Кажется слишком просто!

Ну, мы проигнорировали эти 2 дополнительных параметра в Reducer Анкет Также ИСТИНАЛЬНАЯ ВАЛА в уменьшить Должно быть необязательным, но это требуется в нашей версии. Мы доберемся до этого позже.

Можно сказать, что карта является производным уменьшить Анкет В этом случае мы можем использовать наш Reducer Сверху передайте это уменьшить и предоставить начальное значение [] . Начальное значение – [] Потому что наш результат будет Массив Анкет

const map = (items, func) => {
//                    |
//        function to modify value
  const initialValue = []
  const reducer = (acc, cur) => {
    acc.push(func(cur))
//            |
//      execute func on the currentValue
    return acc
  }
  return reduce(items, reducer, initialValue)
}

const double = x => x * 2

map(items, double) //=> [ 2, 4, 6, 8 ]

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

const filter = (items, predicate) => {
//                         |
//       if truthy, append to accumulator
  const initialValue = []
  const reducer = (acc, cur) => {
    if (predicate(cur)) {
//         |
// run predicate on currentValue
      acc.push(cur)
    }
    return acc
  }
  return reduce(items, reducer, initialValue)
}

const isEven = x => x % 2 === 0

filter(items, isEven) //=> [ 2, 4 ]

ИСТИНАЛЬНАЯ ВАЛА в уменьшить должен быть необязательным. Мы должны быть в состоянии сделать это и получить результат 10 , вместо этого мы получаем НАН Анкет

const add = (acc, cur) => acc + cur

const items = [ 1, 2, 3, 4 ]

reduce(items, add) //=> NaN

Как бы вы сделали ИСТИНАЛЬНАЯ ВАЛА необязательный? Покажите свой код в комментариях.

Я упоминал выше, что редуктор берет 4 аргумента. Все 4 аргумента:

  • Аккумулятор (аккумулятор)
  • Текущее значение (CurrrentValue)
  • Текущий индекс (CurrentIndex)
  • Массив источника (источник)

Мы уже реализовали аккумулятор и текущая стоимость . Как бы вы реализовали CurrentIndex и Источник ? Покажите мне свой код в комментариях.

Изменить уменьшить работать с обоими Массив и Итератор Анкет Это что -то Массив Снижение не может сделать.

// range is an Iterator.
const range = require('mojiscript/list/range')

const reduce = (items, reducer, initialValue) => {
  let acc = initialValue
  for (let i = 0; i < items.length; i++) {
    const cur = items[i]
    acc = reducer(acc, cur)
  }
  return acc
}

const add = (acc, cur) => acc + cur

// Make this return 10
reduce(range(0)(5), add, 0)

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

const predicate = (acc, cur) => acc + cur < 7

const reduce = (items, predicate, reducer, initialValue) => {
  /* solution goes here */
}

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

  • предикат
  • редуктор
  • Начальное значение
  • список

После деконструкции карта , фильтр и уменьшить Чтобы узнать свои внутренние секреты, они становятся намного более доступными для нас.

Это легко увидеть, создав свой собственный уменьшить , вы можете расширить такие функции, как возможность поддержать Итератор или разорвать рано. Я пошел еще дальше с Mojiscript’s уменьшить Поддерживая асинхронный итератор а также Асинхровый редуктор Анкет

Было ли что -то, что ты хотел бы, чтобы я занялся более подробно? Вы что -то узнали, прочитав эту статью? Дай мне знать в комментариях!

Если вы любите функциональный JavaScript, следуйте за мной здесь или в Twitter @joelnet !

Оригинал: “https://dev.to/joelnet/deconstructing-map-filter-and-reduce-1d1a”