В статье приведено 15 примеров использование в Javascript функций map(), reduce() и filter() . Когда вы читаете о Array.reduce и о том как это круто, вы часто можете встретить один и то же пример, показывающий использование этой функции. Этот пример демонстрирует суммирование списка чисел. Проблема с этим примером в том что, я никогда не видел использование этого примера в реальных проектах. Тем не менее, я часто вижу лишних 7–8 строк операторов цикла для решения довольно обычных задач, которые при использование Array.reduce всегда можно преобразовать в одну строку.
Недавно я прорефакторил несколько модулей с использованием этих замечательных функций и был шокирован тем, насколько удобнее стало читать код. Итак, ниже приведен список вкусностей. Также не стесняйтесь размещать свои примеры в разделе комментариев.
Давайте начнем!
Это единственный пример, который не относится в нашем обзоре, к map/reduce/filter, но он настолько компактный, что трудно было не поместить его в список. Кроме того, мы будем использовать похожий код в нескольких примерах.
let values = [3, 1, 3, 5, 2, 4, 4, 4]; let uniqueValues = [...new Set(values)]; // uniqueValues is [3, 1, 5, 2, 4]
Метод filter() создает новый массив со всеми элементами, которые проходят условие, реализованного предоставленной функцией.
let users = [ { id: 11, name: 'Adam', age: 23, group: 'editor' }, { id: 47, name: 'John', age: 28, group: 'admin' }, { id: 85, name: 'William', age: 34, group: 'editor' }, { id: 97, name: 'Oliver', age: 28, group: 'admin' } ]; let res = users.filter(it => it.name.includes('oli')); // res is []
let res = users.filter(it => new RegExp('oli', "i").test(it.name)); // res is [ { id: 97, name: 'Oliver', age: 28, group: 'admin' } ]
Метод some() проверяет, соответствует ли хотя бы один элемент в массиве условию, реализованному в предоставленной функцией.
let hasAdmin = users.some(user => user.group === 'admin'); // hasAdmin is true
Код решает задачу преобразования массива массивов в один плоский массив. Результат первой итерации будет равен: […[], …[1, 2, 3]] что означает, что он преобразуется в [1, 2, 3] — это значение мы предоставляем как ‘acc’ на второй итерации и так далее.
let nested = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; let flat = nested.reduce((acc, it) => [...acc, ...it], []); // flat is [1, 2, 3, 4, 5, 6, 7, 8, 9]
Вероятно, это самая короткая реализация для создания массива (метод Array.flat все еще является экспериментальной функцией). Обратите внимание на то, что использование оператора spread внутри функции reduce не очень хорошо с точки зрения производительности. Этот пример того случая, когда производительностью можно пренебречь только если позволяет контекст использования ☝️
Давайте сгруппируем и посчитаем свойство ‘age’ для каждого элемента в массиве:
let users = [ { id: 11, name: 'Adam', age: 23, group: 'editor' }, { id: 47, name: 'John', age: 28, group: 'admin' }, { id: 85, name: 'William', age: 34, group: 'editor' }, { id: 97, name: 'Oliver', age: 28, group: 'admin' } ]; let groupByAge = users.reduce((acc, it) => ({ ...acc, [it.age]: (acc[it.age] || 0) + 1 }), {}); // groupByAge is {23: 1, 28: 2, 34: 1}
Вместо того, чтобы проходить через весь массив во время поиска пользователя по идентификатору, мы можем создать объект, в котором идентификатор пользователя представляет ключ (с постоянным временем поиска).
let uTable = users.reduce((acc, it) => ({...acc, [it.id]: it }), {}) // uTable equals: { 11: { id: 11, name: 'Adam', age: 23, group: 'editor' }, 47: { id: 47, name: 'John', age: 28, group: 'admin' }, 85: { id: 85, name: 'William', age: 34, group: 'editor' }, 97: { id: 97, name: 'Oliver', age: 28, group: 'admin' } }
Это особенно полезно когда вам часто приходится обращаться к данным следующим образом uTable[85].name
a lot.
Давайте создадим список групп пользователей. Метод map() создаст новый массив с результатами вызова предоставленной функции для каждого элемента в вызывающем массиве.
let listOfUserGroups = [...new Set(users.map(it => it.group))]; // listOfUserGroups is ['editor', 'admin'];
let cities = { Lyon: 'France', Berlin: 'Germany', Paris: 'France' }; let countries = Object.keys(cities).reduce( (acc, k) => (acc[cities[k]] = [...(acc[cities[k]] || []), k], acc) , {}); // countries is { France: ["Lyon", "Paris"], Germany: ["Berlin"] }
Этот однострочник выглядит довольно сложно. Мы используем оператор comma (запятая), что означает, что мы возвращаем последнее значение в скобках — acc. Давайте перепишем этот пример более production-ready способом:
let countries = Object.keys(cities).reduce((acc, k) => { let country = cities[k]; acc[country] = [...(acc[country] || []), k]; return acc; }, {});
Думайте об этом примере как о примере с обработкой каждого элемента массива заданной формулой 🤓
let celsius = [-15, -5, 0, 10, 16, 20, 24, 32] let fahrenheit = celsius.map(t => t * 1.8 + 32); // fahrenheit is [5, 23, 32, 50, 60.8, 68, 75.2, 89.6]
let params = {lat: 45, lng: 6, alt: 1000}; let queryString = Object.entries(params).map(p => encodeURIComponent(p[0]) + '=' + encodeURIComponent(p[1])).join('&') // queryString is "lat=45&lng=6&alt=1000"
В определенных случаях вам может понадобится отобразить массив объектов с выбранными ключами в виде строки, но без использования JSON.stringify . 😦Например из-за необходимость исключение определенных ключей.
let users = [ { id: 11, name: 'Adam', age: 23, group: 'editor' }, { id: 47, name: 'John', age: 28, group: 'admin' }, { id: 85, name: 'William', age: 34, group: 'editor' }, { id: 97, name: 'Oliver', age: 28, group: 'admin' } ]; users.map(({id, age, group}) => `\n${id} ${age} ${group}`).join('') // it returns: " 11 23 editor 47 28 admin 85 34 editor 97 28 admin"
Допустим нам понадобилось изменить возраст Джона. Если мы будем знать индекс, мы можем легко это сделать с помощью: users[1].age = 29
. Однако у нас есть и другая возможность это сделать:
let updatedUsers = users.map( p => p.id !== 47 ? p : {...p, age: p.age + 1} ); // John is turning 29 now
Здесь вместо того, чтобы изменять один элемент в нашем массиве, мы создаем новый массив с отличием только в одном элементе. Теперь мы можем сравнивать наши массивы только по ссылкам updatedUsers == users, что очень быстро работает! React.js использует такой же подход для ускорения процесса согласования. Подробнее об этом можно почитать здесь.
С меньшим кодом чем использование метода lodash union.
let arrA = [1, 4, 3, 2]; let arrB = [5, 2, 6, 7, 1]; [...new Set([...arrA, ...arrB])]; // returns [1, 4, 3, 2, 5, 6, 7]
Это последний пример!
let arrA = [1, 4, 3, 2]; let arrB = [5, 2, 6, 7, 1]; arrA.filter(it => arrB.includes(it)); // returns [1, 2]
В качестве упражнения можете попытаться реализовать поиск разницы в массивах (A \ B). Подсказка: используйте восклицательный знак.
Надеюсь моя статься окажется вам полезной. Если у вас есть какие-либо вопросы или пожелания, дайте мне знать в комментариях ниже.
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
привет. помоги решить задачку. вот задача
Реализуйте и экспортируйте по умолчанию функцию, которая переводит входные данные в удобный для построения графика формат.
На вход эта функция принимает массив данных. Каждая запись массива представляет из себя объект типа { value: 14, date: '02.08.2018' }. Например:
const data = [
{ value: 14, date: '02.08.2018' },
{ value: 43, date: '03.08.2018' },
{ value: 38, date: '05.08.2018' },
];
Вторым и третьим параметрами функция принимает даты (в форме строк типа 'YYYY-MM-DD') начала и конца периода:
const begin = '2018-08-01';
const end = '2018-08-06';
Диапазон дат задаёт размер выходного массива, который должна сгенерировать реализуемая функция. Правила формирования итогового массива:
он заполняется записями по всем дням из диапазона begin - end
в него включаются только те записи из входного массива, даты которых попадают в диапазон
если во входном массиве нет данных для какого-то дня из диапазона, то в свойство value записи этого дня установить значение 0
const result = normalizeData(data, beginDate, endDate);
console.log(result);
// OUTPUT
[ { value: 0, date: '01.08.2018' },
{ value: 14, date: '02.08.2018' },
{ value: 43, date: '03.08.2018' },
{ value: 0, date: '04.08.2018' },
{ value: 38, date: '05.08.2018' },
{ value: 0, date: '06.08.2018' } ]
Подсказки
Обратите внимание, что в практике импортированы функции для работы c датами, коллекциями и объектами. При необходимости вы можете (это необязательное требование) ими воспользоваться.
Даты: https://date-fns.org/
вот начало моего решения
const normalizeData = (date, begin, end) => {
const eachDay = eachDayOfInterval({start: new Date(begin), end: new Date(end)});
const formatData = eachDay.map(e => format(e, 'dd.MM.yyyy'));
}
Отличная статья!!!
всем привет можете помочь с одной задачкой
Напишите функцию, которая получает массив функций и начальное значение, как аргументы. Функция должна вернуть результат выполнения всех функций в массиве поочередно, используя начальное значение. Используйте reduce.
Например
[
(a) => a+ 1,
(a) => a * 2
],
5
5 начальное значение.
Сначала запускается функция с ((a) => a+ 1)(5). Результат будет 6. теперь 6 используется во второй функции
((a) => a * 2)(6)
Итог 12
Количество функций в начальном массиве не ограничено
Чтобы решить эту задачу - четко решите, что будет являться аккумулятором, что будет являться ресивером в редьюсе. Какие у них типы. Как пройдет редьюс в первом шаге и что он вернет.
Задача решается в одну строчку, но тяжела для понимания. Ключ решения - ясность.
Input: [ (a) => a+ 1, (a) => a * 2 ], 5
Actions:
Output: 12
Input: [ (a) => a - 1, (a) => a * 2 ], 5
Actions:
Output: 8
Input: [ (a) => a + 2, (a) => a * 5, (a) => a - 5 ], 3
Actions:
Output: 20