Share This
Связаться со мной
Крути в низ
Categories
//map(), filter() и reduce() в JavaScript

map(), filter() и reduce() в JavaScript

Код на JavaScript можно сделать более функциональным, попутно облегчив труд программиста. Знакомимся с методами массивов map(), filter() и reduce(). Обсудить

map filter i reduce v javascript c2d413b - map(), filter() и reduce() в JavaScript

Перевод публикуется с сокращениями, автор оригинальной статьи Aditya Dhanraj Tiwari.

Методы массивов map, filter и reduce – по сути, лишь некоторые из наиболее известных и простых в использовании функций высшего порядка, которые обеспечивают обратный вызов для каждого элемента. В этой статье мы рассмотрим, как применение map(), filter() и reduce() поможет сделать код:

  • понятным;
  • менее подверженным побочным эффектам, т. к. эти методы не изменяют массив, а создают новый;
  • избегающим явных циклов.

Приступим к рассмотрению.

Примечание переводчика Обратный вызов позволяет в функции исполнять заданный в аргументе код, который может быть недоступен для прямого вызова. Часто такой подход используется для реализации алгоритма обхода некого хранилища объектов и определенных действий с его элементами. Функция высшего порядка может принимать в качестве аргументов другие функции или возвращать функцию в качестве результата. В этом случае функции имеют тот же статус, что и прочие объекты данных. Такой подход позволяет делать сложные программы компактными. Array.map()

Представим ситуацию, в которой есть несколько записей для студентов с атрибутами: name, ID и marks.

         let studentRecords = [ {name: 'John', id: 123, marks : 98 },           {name: 'Baba', id: 101, marks : 23 },           {name: 'yaga', id: 200, marks : 45 },           {name: 'Wick', id: 115, marks : 75 } ]      

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

Ожидаемый результат:

         ['JOHN', 'BABA', 'YAGA', 'WICK']     

Существует несколько способов достижения цели:

         1. for() loop  let names = []; for (let index = 0; index < studentRecords.length; index++){      names.push(studentRecords[index].name.toUpperCase()); } console.log(names); // logs: [ 'JOHN', 'BABA', 'JOHN', 'WICK' ]  2. for(...of)  let names = [] for (const student of studentRecords) {     names.push(student.name.toUpperCase()); } console.log(names); // logs: [ 'JOHN', 'BABA', 'JOHN', 'WICK' ]  3. forEach() let names = [] studentRecords.forEach( student => {      names.push(student.name.toUpperCase()); }) console.log(names); // logs: [ 'JOHN', 'BABA', 'JOHN', 'WICK' ]     

Во всех вышеупомянутых примерах создается пустой массив для хранения результата. Как в for(...of), так и в for() нужно явно перебирать массивы, что делает код более запутанным.

Решение с помощью map()

         let names = studentRecords.map( stu => stu.name.toUpperCase()); console.log(names); // logs: [ 'JOHN', 'BABA', 'JOHN', 'WICK' ]     

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

Работа map():

         Array.map( callback, thisValue )      

Метод map() принимает два аргумента: функцию обратного вызова и необязательное значение объекта.

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

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

Array.filter()

filter() возвращает только те элементы из массива, которые удовлетворяют заданным критериям.

Постановка задачи: предположим, что у нас есть тот же набор данных, что и выше, но на этот раз мы хотим получить подробную информацию о студентах, набравших более 50 баллов.

Ожидаемый результат:

         [{name: 'John', id: 123, marks : 98 },{name: 'Wick', id: 115, marks : 75 }]     

Решение: используем filter() для выбора записей, удовлетворяющих заданному условию (т. е. больше 50 баллов).

         let names = studentRecords.filter(stu => stu.marks > 50); console.log(names); // logs: [ { name: 'John', id: 123, marks: 98 },{ name: 'Wick', id: 115, marks: 75 }]     

Постановка задачи: получить информацию о студентах, набравших более 50 баллов и имеющих id больше 120.

         let names = studentRecords.filter(stu => stu.marks > 50 && stu.id > 120) console.log(names); //logs: [ { name: 'John', id: 123, marks: 98 } ]     

Решение: как показано в приведенном выше фрагменте кода, используя filter() с несколькими условиями для фильтрации данных, мы можем эффективно справиться с задачей.

Работа filter():

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

Array.reduce()

Точно так же, как map() и filter(), reduce() выполняет обратный вызов для каждого элемента массива. Чтобы лучше понять reduce, сначала нужно рассмотреть два термина: «accumulator» и «reducer».

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

Постановка задачи: на этот раз необходимо знать общую сумму баллов студентов.

         let totalMarks = studentRecords.reduce( ((acc,emp) => acc+emp.marks), 0) console.log(totalMarks);// logs: 241     

Решение:

         Array.reduce( (accumulator,curr_value) => expression ), intialValue)     

Работа reduce():

Давайте разберемся в работе reducer шаг за шагом:

  1. reduce() принимает accumulator, текущее значение, выражение и initialValue в качестве параметра, используемого для инициализации accumulator (обратите внимание, что в нашем примере initialValue = 0);
  2. reduce() принимает первый элемент массива в качестве текущего значения и accumulator, а затем выполняет требуемую операцию (как при сложении двух значений в нашем примере) и сохраняет результат в accumulator;
  3. Затем accumulator заменяется ранее рассчитанным accumulator, и текущее значение устанавливается на второй элемент массива. Необходимая операция выполняется и accumulator обновляется с новым результатом.
  4. Шаг 3 выполняется, пока все элементы массива не будут перебраны.
  5. Метод возвращает значение accumulator.

Чтобы сравнить наши знания с фактической работой reduce(), рассмотрим значения «accumulator» и «curr_value» для каждой итерации из приведенного выше примера.

         let totalMarks =        studentRecords.reduce( function(accumulator,curr_value){           console.log(`accumulator: ${accumulator}, curr_value:$                                     curr_value.marks}`);           return accumulator + curr_value.marks;}, 0) console.log(totalMarks); // logs ------- accumulator: 0 , curr_value: 98 accumulator: 98 , curr_value: 23 accumulator: 121 , curr_value: 45 accumulator: 166 , curr_value: 75 241     

Из журнала видно, что accumulator начинается со значения 0 и на каждом шаге его значение обновляется суммой «previous value» и «curr_value».

Теперь объединим возможности map(), filter() и reduce()

Пример 1. map() и filter()

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

         let names = studentRecords.filter(stu => stu.marks > 50).map(stu => stu.name) console.log(names); // logs: [ 'John', 'Wick' ]     

Решение: сначала мы отфильтровали данные с помощью filter(), а затем использовали map(), чтобы получить только атрибут name.

Примечание: Вы можете связать map() и filter(), так как они возвращают массивы.

Пример 2. filter() и reduce()

Постановка задачи: напечатаем сумму баллов студентов с id больше 120.

         let totalMarks = studentRecords.filter(stu => stu.id > 120).reduce((acc,curr) => acc + curr.marks ,0) console.log(totalMarks); // logs: 143     

Решение: сначала выбрали студентов с идентификатором больше 120 с помощью filter(), а потом передали отфильтрованный массив студентов в reduce(), чтобы получить сумму их баллов.

Примечание: вы можете связать reduce() после map() и filter(), поскольку они возвращают массивы, но не можете связать map() и filter() после reduce(), т. к. он возвращает единственное значение.

Пример 3. map(), filter() и reduce()

Постановка задачи: вывести общее количество студентов с баллами больше 50, полученными после начисления поощрения в 15 баллов.

         let studentRecords = [ {name: 'John', id: 123, marks : 98 },                   {name: 'Baba', id: 101, marks : 23 },                   {name: 'John', id: 200, marks : 45 },                   {name: 'Wick', id: 115, marks : 75 }, ] let totalMarks = studentRecords.map(function(stu){              if(stu.marks < 50){                 stu.marks += 15;}             return stu;         }).filter(stu => stu.marks > 50).reduce((acc,curr) => acc+curr.marks, 0); console.log(totalMarks); //logs : 233     

Решение:

  1. Используя map(), добавляется поощрение в 15 баллов студентам, набравшим менее 50 баллов.
  2. Затем, используем filter() для массива студентов, возвращаемого функцией map(). Так мы найдем всех студентов с отметками больше 50.
  3. Наконец, мы использовали функцию reduce() для возвращаемого функцией filter() массива студентов, чтобы вернуть сумму оценок.

Заключение

В этом гайде мы разобрались, как map(), filter() и reduce() могут облегчить жизнь разработчику, сократив количество ненужных явных циклов и объявлений пустых массивов. Это сделает код более функциональным и легким для понимания. Попробуйте заменять циклы этими методами всякий раз, когда у вас появится такая возможность. Удачи!

Дополнительные материалы:

  • Прощай, плохой код: вот как не лажать в JavaScript
  • Разбираем на примерах: как избежать мутаций в JavaScript
  • Учи JavaScript правильно. Путеводитель для растерявшихся
  • Всегда чистый код: 5 инструментов для JavaScript-разработчика
  • Где JavaScript джуну получать тестовые задания для практики?

  • 1 views
  • 0 Comment

Leave a Reply

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    Roman Spiridonov
    Roman Spiridonov

    Привет ! Мне 38 лет, я работаю в области информационных технологий более 4 лет. Тут собрано самое интересное.

    Our Instagram 04.

    Categories 05.

    © Speccy 2020 / All rights reserved

    Связаться со мной
    Close