Мы все должны согласиться с тем, что JavaScript - это здорово! Но вы знаете, что? LEGO еще лучше! Почему? Потому что с помощью этой удивительной игрушки вы можете объяснить и смоделировать так много идей, моделей поведения и алгоритмов 🚀.
Определение
Сеть разработчиков Mozilla определяет метод сокращения в прототипе объекта Array следующим образом:
Метод
reduce()
выполняет функцию редуктора (которую вы предоставляете) для каждого члена массива, в результате чего получается одно выходное значение.
Возвращаемое значение вашей функции reducer присваивается аккумулятору, значение которого запоминается на каждой итерации по всему массиву и в конечном итоге становится окончательным единичным результирующим значением.
Хорошо, но когда и как я могу использовать эту функцию? Это только для суммирования всех чисел в массиве? Есть реальный пример? И что означают этот аккумулятор (acc
), текущее значение (cur
), текущий индекс (idx
) и исходный массив (src
)?
🧒🏻 Давайте погрузимся в детскую комнату за красивым объяснением.
Разноцветные блоки
Честно говоря, я совершенно неисправимый наркоман LEGO 🤪. Ах, эти цвета, формы и возможности построить из них все, что только можно вообразить ...
Теперь, когда у меня не так много времени на них, я предпочитаю, чтобы все наборы были собраны и выставлены на полке так, как они должны выглядеть в соответствии с моделью. Но время от времени (особенно когда дети получают в руки мою драгоценную коллекцию) все мои наборы смешиваются и вместе выбрасываются в большой контейнер. Ох, какой беспорядок ... А потом приходит время собрать все свои припасы, силы и мотивацию, чтобы вернуть их на свои полки.
Но подождите, а как насчет редукторов? Итак, прежде чем я смогу восстановить свою отображаемую коллекцию, мне нужно построить их, и для этого мне нужно знать, какая часть принадлежит какому набору. Тогда я смогу составить наборы с их инструкциями (как будто я не знаю инструкции наизусть 😁).
И вот пришло время моему мозгу использовать идеальный редуктор массива!
Давайте уменьшим кирпичи
Хорошо, поэтому для простоты примера предположим, что среди разных наборов нет общих блоков. Итак, я знаю, что если я увижу черный блок 2x2, я знаю, что он принадлежит моему B-Wing Fighter из Звездных войн, а все мои красные окна принадлежат старому семейному дому установить. Предположим, у меня есть только 3 набора LEGO: крыло B, комната запретного коридора Гарри Поттера и простой старый дом с белыми стенами и красной крышей.
Итак, вот мой контейнер со всеми перепутанными кирпичиками.
const bricks = [ {set: 'b-wing', type: 'brick', size: '2x2', color: 'black'}, {set: 'house', type: 'roof', size: '4x2', color: 'red'}, {set: 'hp', type: 'spider', size: '1x1', color: 'black'}, {set: 'b-wing', type: 'panel', size: '4x8', color: 'gray'}, {set: 'b-wing', type: 'brick', size: '2x2', color: 'black'}, {set: 'house', type: 'brick', size: '6x1', color: 'white'} ]
Я хочу разложить их по коробкам с наборами LEGO следующим образом:
{'b-wing': [], 'house': [], 'hp': []}
📥📥📥 Я не подготовил коробки с этикетками, поэтому буду делать это попутно, как только наткнусь на предмет, на котором еще нет коробки.
Итак, что я собираюсь сделать, это перебрать все кирпичи и поместить каждый из них в соответствующую коробку. Вот некоторые утверждения из процесса:
- Первоначально у меня нет коробок для каждого набора, но я знаю, что собираюсь поставить коробки на специальной полке.
- Я вынимаю новый кирпич из исходного контейнера, обрабатываю его в уме, решаю, где он принадлежит, и помещаю текущий кирпич в установленную коробку.
- Если для набора моей текущей части нет коробки, я создаю, маркирую новую коробку и кладу ее на полку.
- Каждый раз, когда я беру кирпич из исходного контейнера, я уменьшаю количество всех кирпичей, оставшихся для расстановки.
- Наконец, когда в исходном контейнере не осталось кирпичей для обработки, я смотрю на свою полку и вижу, что в моей смешанной кучке кубиков LEGO осталось превратился в структурированный набор помеченных коробок на моей полке.
Другими словами (или визуально) я преобразую стопку слева в организованную структуру справа:
👩🏻💻 Если бы кто-то закодировал весь этот процесс на JavaScript, используя метод Array.reduce()
, это выглядело бы так:
const bricks = [....]; //the pile of bricks defined above const shelf = bricks.reduce((shelfOfBoxes, brick, brickNumber, pile) => { console.log(`Checking the brick number ${brickNumber + 1}`); if(!shelfOfBoxes.hasOwnProperty(brick.set)) { shelfOfBoxes[brick.set] = []; //add a new box if needed } shelfOfBoxes[brick.set].push(brick); //put the brick in its box console.log(`Bricks left: ${pile.length - (brickNumber + 1)}`) }, {}); //the empty shelf console.log(shelf);
А что у нас здесь?
- Изначально у меня есть смешанная кучка кирпичей, хранящаяся в массиве
- Изначально моя полка пуста. Второй аргумент в функции уменьшения - это начальное значение полки, которое является пустым объектом:
{}
- Я просматриваю массив с помощью метода уменьшения
- На каждой итерации цикла я знаю следующее: текущая ситуация на полке (
shelfOfBoxes
), текущий кирпич, который я обрабатываю (brick
), который является текущим индексом кирпича / сколько я уже обработал (brickNumber
) и начальная связка кирпичей (pile
) - Во время каждого цикла я проверяю, есть ли на полке поле с заданным именем для моего текущего кирпича:
if(!shelfOfBoxes.hasOwnProperty(brick.set))
- Если ящика нет, я добавляю новое пустое поле с меткой текущего кирпича, установленного на полке:
shelfOfBoxes[brick.set] = [];
- Затем кладу текущий кирпич в коробку для его набора:
shelfOfBoxes[brick.set].push(brick);
- Отмечу для себя, сколько кирпичей осталось в куче:
console.log(`Bricks left: ${pile.length — (brickNumber + 1)}`)
- В итоге у меня есть
shelf
ящиков, заполненных всеми кубиками, принадлежащими каждому сетевому ящику.
Поэтому я использовал функцию reducer, чтобы преобразовать массив объектов во что-то совершенно другое. В этом цель метода Array.reduce()
.
Выполнено
Круто, теперь вы должны иметь представление о том, что такое reduce
метод, каковы его аргументы и каков реальный пример, когда наш мозг работает как редуктор 🧠.
Конечно, у метода Array.reduce()
есть и другие возможности и варианты использования. Вы также должны знать, что начальное значение преобразования необязательно. Я уже знаю другой пример, связанный с кирпичом для этого случая. Следите за новой статьей с подробным объяснением в ближайшее время 📢.
И, конечно же: