.flatMap() — JavaScript — Дока

Кратко

Скопировано

Метод flatMap() позволяет сформировать массив, применяя функцию к каждому элементу, затем уменьшает вложенность, делая этот массив плоским, и возвращает его.

Был добавлен в стандарте ES2019. Если вы поддерживаете браузеры, выпущенные раньше 2018 года, то вам понадобится полифил.

Пример

Скопировано

Получить плоский список из сложной структуры

Скопировано

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

const orders = [    {        id: 1,        products: [            { name: 'Чизкейк', price: 1.99 },            { name: 'Бисквит', price: 4.99 },        ]    },    {        id: 2,        products: [            { name: 'Шоколад', price: 5.59 },            { name: 'Зефир', price: 8.99 },        ]    }]
          const orders = [
    {
        id: 1,
        products: [
            { name: 'Чизкейк', price: 1. 99 },
            { name: 'Бисквит', price: 4.99 },
        ]
    },
    {
        id: 2,
        products: [
            { name: 'Шоколад', price: 5.59 },
            { name: 'Зефир', price: 8.99 },
        ]
    }
]

Одним из решений будет сначала дважды вызвать метод map(), а затем сделать массив плоским с помощью метода flat

()

Сначала воспользуемся методом map():

orders.map(  (order) => order.products.map(product => product.name))
          orders.map(
  (order) => order.products.map(product => product.name)
)

Получим следующий результат:

[['Чизкейк', 'Бисквит'], ['Шоколад', 'Зефир']]
          [['Чизкейк', 'Бисквит'], ['Шоколад', 'Зефир']]

Обратите внимание на вложенность массивов, нам нужно от неё избавиться. Для этого применим метод flat():

orders  .
map((order) => order.products.map((product) => product.name)) .flat() orders .map((order) => order.products.map((product) => product.name)) .flat()
['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']
          ['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']

Другое решение этой задачи — сразу вызвать метод flatMap() (ведь статья у нас именно про него):

orders.flatMap(  (order) => order.products.map(product => product.name))
          orders.flatMap(
  (order) => order.products.map(product => product.name)
)

Увидим что функция применилась, вложенность уменьшилась и мы получили только названия продуктов из массива

products:

['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']
          ['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']

Модификация структуры данных

Скопировано

Представим, что мы пишем корзину для интернет-магазина. Товары в корзине храним в виде объекта:

const cart = [  {    name: 'Телефон',    count: 1,    price: 500,  },  {    name: 'Ноутбук',    count: 1,    price: 800,  }]
          const cart = [
  {
    name: 'Телефон',
    count: 1,
    price: 500,
  },
  {
    name: 'Ноутбук',
    count: 1,
    price: 800,
  }
]

Если человек покупает телефон, то требуется добавить зарядное устройство. Для этого вызовем flatMap() и будем возвращать массив из телефона и зарядного устройства вместо одного объекта с телефоном.

cart.flatMap(  (item) => {    if (item.name === 'Телефон') {      return [item, {        name: 'Зарядное устройство',        count: item.count,        price: 50,      }]    }    return item  })
          cart.flatMap(
  (item) => {
    if (item.name === 'Телефон') {
      return [item, {
        name: 'Зарядное устройство',
        count: item.count,
        price: 50,
      }]
    }
    return item
  }
)

flatMap() сделает массив плоским и мы получим массив элементов в корзине:

[  {    name:'Телефон',    count:1,    price:500,  }, {    name:'Зарядное устройство',    count:1,    price:50,  }, {    name:'Ноутбук',    count:1,    price:800,  },]
          [
  {
    name:'Телефон',
    count:1,
    price:500,
  }, {
    name:'Зарядное устройство',
    count:1,
    price:50,
  }, {
    name:'Ноутбук',
    count:1,
    price:800,
  },
]

Эту же задачу можно решить и другим способом, применив метод reduce().

Но это отразится на читаемости кода, а этим пренебрегать не стоит!

cart.reduce((list, item) => {    if (item.name === 'Телефон') {      list.push(item, {        name: 'Зарядное устройство',        count: item.count,        price: 50,      })    } else {        list.push(item)    }    return list}, [])
          cart.reduce((list, item) => {
    if (item.name === 'Телефон') {
      list.push(item, {
        name: 'Зарядное устройство',
        count: item.count,
        price: 50,
      })
    } else {
        list.push(item)
    }
    return list
}, [])

Как пишется

Скопировано

Как и другим похожим методам, flatMap() необходимо передать колбэк-функцию, которая будет возвращать какое-то значение. Именно это значение попадёт в итоговый массив.

Функция, которую мы передаём в flatMap(), принимает три аргумента:

  • currentValue — текущий элемент массива.
  • index — индекс текущего элемента в массиве.
  • array — массив, который мы перебираем.

Возвращает 0 или более элементов массива.

Как понять

Скопировано

Метод идентичен последовательному вызову map().flat() с параметром depth = 1, соответственно, применяется для трансформации исходных данных, с уменьшением вложенности.

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

Разница между

map() и flatMap() Скопировано

Рассмотрим на примере разницу между методами

map() и flatMap(). Возьмём массив с данными о местоположении и представим, что нужно получить (или преобразовать) координаты:

const allActivities = [  { title: 'Офис', coordinates: [50.123, 3.291] },  { title: 'Спортзал', coordinates: [1.238, 4.292] },]const mappedCoordinates = allActivities.map(activity => activity.coordinates)const flatMappedCoordinates = allActivities.flatMap(activity => activity.coordinates)
          const allActivities = [
  { title: 'Офис', coordinates: [50.123, 3.291] },
  { title: 'Спортзал', coordinates: [1.238, 4.292] },
]
const mappedCoordinates = allActivities.map(activity => activity.coordinates)
const flatMappedCoordinates = allActivities.flatMap(activity => activity.coordinates)

Теперь взглянем на результаты с применением map():

[[50.123, 3.291], [1.238, 4.292]]
          [[50.123, 3.291], [1.238, 4.292]]

И на результат с flatMap():

[50.
123, 3.291, 1.238, 4.292] [50.123, 3.291, 1.238, 4.292]

Вместо того чтобы использовать метод map() и получить массивы координат, а затем сократить массив, вы можете сразу использовать flatMap().

Разница между flat() и flatMap()

Скопировано

Метод flat() делает входной массив плоским, глубина указывается в аргументах.
Метод flatMap() применяет функцию, трансформируя массив и делает массив плоским. Два в одном.

Как получить все неуникальные значения в массиве JavaScript?

Иногда бывает нужно получить все повторяющиеся значения из массива JavaScript.

В этой статье мы рассмотрим способы получения всех неуникальных значений в массиве JavaScript.

Array.prototype.filter

Один из таких способов связан с использованием метода filter массива JavaScript для возвращения массива, соответствующего заданному условию.

Он принимает функцию обратного вызова, возвращающую условие, которое должно быть у каждого возвращаемого элемента.

Задействуя метод filter вместе с вызовом метода indexOf в функции обратного вызова, мы проверяем, является ли встреченный элемент первым.

Для этого в массиве, в котором вызывается filter, вызываем indexOf, получаемый из третьего параметра функции обратного вызова.

Затем проверяем, совпадает ли возвращаемый индекс с тем, которому соответствует итерируемый элемент.

Например, напишем следующее:

const duplicates = [1, 2, 2, 4, 3, 4].filter((e, index, arr) => arr.indexOf(e) !== index)
console.log(duplicates)

Затем вызываем filter с функцией обратного вызова, которая принимает параметры e, index и arr, где:

  • e  —  это элемент, по которому выполняется итеративный обход;
  • index  —  это индекс элемента e;
  • arr  —  это массив, в котором вызывается filter.

Мы вызываем indexOf в arr с аргументом e, чтобы вернуть индекс первого встреченного элемента e в массиве arr.

Несовпадение ​возвращаемого индекса с index свидетельствует о том, что это встреченное значение не первое.

Следовательно, duplicates (повторяющиеся значения)  —  это [2, 4], так как они дублируются в массиве.

Подсчет элементов

Посчитаем элементы в массиве, создав собственный объект для задания значения счетчика:

const obj = [1, 2, 2, 4, 3, 4]
  .map((val) => {
    return {
      count: 1,
      val
    }
  })
  .reduce((a, b) => {
    a[b.val] = (a[b.val] || 0) + b.count
    return a
  }, {})const duplicates = Object.entries(obj)
  .filter(([, val]) => {
    return val > 1
  })
  .map(([key]) => +key)
console.log(duplicates)

Вызываем map для сопоставления каждой записи объекту со счетчиком count, имеющим значение 1, и со значением элемента массива val.

Затем вызываем reduce для создания объекта со счетчиком каждого элемента, где каждый элемент будет ключом.

Делаем это, присваивая счетчик из a[b.val] с (a[b.val] || 0) + b.count.

В b.count имеется новый счетчик.

И возвращаем a, где содержатся все произведенные подсчеты.

Второй аргумент  —  пустой объект, поэтому создаем объект в конце.

Затем для получения повторяющихся значений мы берем все ключи со значением больше 1.

Для этого вызываем Object.entries в obj.

После чего вызываем filter с функцией обратного вызова для возвращения любых записей со значением val больше 1.

val  —  это значение свойства объекта.

Затем вызываем

map для получения ключа key из массивов, содержащих пары «ключ-значение».

Получаем тот же результат, что и в предыдущем примере для duplicates (повторяющихся значений).

Заключение

Для получения из массива повторяющихся значений используются различные методы массивов и объектов. Мы рассмотрели лишь малую их часть.

Читайте также:

  • Утверждения, применяемые при импортировании в JavaScript
  • JavaScript - идеальный выбор при аналитической обработке данных
  • Советы по отладке JavaScript

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи John Au-Yeung: How to Get All Non-Unique Values in a JavaScript Array?

Читайте также

11 способов перебора массива в Javascript

Ах… Javascript, наш любимый язык, Его свобода может быть как благословением, так и проклятием.

В этом посте мы рассмотрим 11 различных способов (в произвольном порядке) перебора массива (не объекта) в Javascript.


Давайте определим наш массив

Хорошо, это довольно простой массив, давайте двигаться дальше.

1- Верный старый forEach

Array. prototype.forEach

Классический массив forEach принимает два аргумента:

1- Функция, содержащая три параметра: текущий элемент, индекс и исходный массив.
2- A эта замена для передачи функции обратного вызова (игнорируется стрелочными функциями).

Это наиболее рекомендуемый способ итерации, совместимый с IE9

2- Цикл for-in

Такое использование цикла не рекомендуется и иногда используется только для отладки, но вы можете столкнуться с ним в дикой природе, используемой в производстве. Он перебирает любое пользовательское свойство, определенное для объекта, за исключением свойств javascript по умолчанию. Он также работает для циклического перебора массивов, но если вы определите что-либо в прототипе массива, то он также будет полностью повторен.

3 — Цикл for-of (ES6)

Это один из самых щедрых видов циклов, он встроен в саму спецификацию языка. Он очень похож на цикл for-in, но основное различие между ними заключается в том, что for-of используется исключительно для типов коллекций (карты, наборы, массивы, массивы типов, списки узлов и т.  д.). Это позволит избежать свойств объекта и может использоваться с любым объектом, который также реализует символ [Symbol.iterator] (см. Расширенное использование).

Основное отличие от Array.prototype.forEach заключается в том, что вы можете использовать ключевое слово break для остановки цикла и ключевое слово continue для пропуска текущей итерации.

4 — Стиль C для цикла

Это один из наиболее часто используемых массивов в вычислительной технике. Его синтаксис унаследован от языка C и состоит из трех частей:

  • Инициализатор индекса
  • Состояние работы
  • Модификатор индекса, который запускается в конце каждого цикла

Вы также можете использовать ключевые слова break и continue для этого типа цикла.

5 — Цикл «Пока»

Цикл while самый быстрый (по какой-то причине), его синтаксис очень прост:

  • Условие выполнения

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

Вы также можете использовать ключевые слова break и continue для этого типа цикла.

6. Цикл Do-while

Цикл do-while очень похож на цикл while, но он оценивает условие выполнения в конце выполнения, в результате чего цикл всегда выполняется хотя бы один раз. Это заставляет вас обрабатывать сценарий пустого массива, поскольку доступ к пустому массиву приведет к ошибке. Его синтаксис тоже прост:

  • Состояние работы

О, и вы также можете использовать ключевые слова break и continue для такого рода циклов.

7 — Метод Map

Array.prototype.map

В ES5 добавлено три основных метода для итерации массива для создания нового массива. Одним из таких методов является карта .

Функция карты принимает два аргумента:

1- Функция, которая содержит три параметра: текущий элемент, индекс и исходный массив.
2- A эта замена для передачи функции обратного вызова (игнорируется стрелочными функциями).

Не следует изменять исходный массив.

8 — Метод фильтра

Array.prototype.filter

Функция фильтра используется для оценки логического выражения, если возвращается true, то итерируемый элемент остается в новом цикле, если возвращается false, то элемент будет проигнорирован и не будет присутствовать на новый массив.

Как и функция карты, функция фильтра принимает два аргумента:

1- Функция, которая содержит три параметра: текущий элемент, индекс и исходный массив.
2- A эта замена для передачи функции обратного вызова (игнорируется стрелочными функциями).

Не следует изменять исходный массив.

9 — Метод уменьшения

Array.prototype.reduce

Функция reduce отслеживает новый продукт и текущий элемент, а также получает параметр для начального значения нового продукта. Это может быть трудно понять в начале, но чем больше вы смотрите на примеры сокращения, тем легче вам становится понять синтаксис.

Метод сокращения получает следующие входные данные:

1- Функция, которая имеет продукт в качестве первого параметра, а текущий элемент повторяется в качестве второго параметра, третий параметр, который является текущим индексом элемента, и последний параметр, который обеспечивает доступ к исходному массиву.
2- Начальное значение, которое будет использоваться для продукта.

Метод сокращения обычно используется для синтеза всего массива в одно значение, например, для вычисления суммы.

10 — Метод соединения строки и массива

Array.prototype.join

Метод соединения имеет кое-что общее с последним введенным нами методом (reduce): он генерирует один вывод из массива, точнее, строки, и может работать только с массивами на основе строк.

Он имеет единственный ввод: строка-разделитель, которую нужно использовать.

11 — ES2018 для ожидания

Это одна из новейших функций, представленных в javascript, она позволяет нам размещать ожидание в наших циклах for of, позволяя им перебирать промисы и асинхронные значения (см. Функции асинхронного генератора).

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

Другой пример:


ES2019

Flat метод Array.prototype.flat

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

Вы можете указать, насколько глубоко вы хотите углубиться в структуру массива, чтобы вывести значения массива на верхний уровень.

ES2019

Flatmap метод Array.prototype.flatMap

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

(Спасибо Пабло Обандо за эти предложения) 😄

Рекурсия

Вы можете использовать рекурсию для перебора массива, спасибо !

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

1- Вы можете настроить свою петлю так, как хотите.
2- Функциональный подход.
3- Действительно полезно, когда вы имеете дело с другими типами структур, такими как деревья или круговые списки.

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

Вы даже можете создать смесь цикла C Style и цикла forEach!

Давайте продолжим и определим рекурсивную функцию для воспроизведения функциональности Array.prototype.forEach :


Итак, вероятно, есть много способов перебрать массив в javascript, например, обратный do-while петли. или любой из других не очень популярных методов Array.prototype , таких как every , some , reduceRight или flatMap , но вот некоторые из самых популярных способов перебора массива в JavaScript 🚀

Различные способы перебора массива в JavaScript

Несколько способов перебора массива в JavaScript: цикл for, цикл while, цикл for, map(), forEach(), filter() и reduce().

Опубликовано в

·

Чтение: 5 мин.

·

12 августа 2022 г.

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

Что такое массив?

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

Почему мы перебираем массив?

Так как массив хранит элементы в последовательном порядке, нам нужно пройти или перебрать массив, чтобы найти в нем нужный элемент. Обычно обход занимает время сложности O(n). Мы также пройдемся по массиву, чтобы изменить элементы массива или получить доступ к каждому элементу массива.

Различные методы обхода массива

Существует несколько методов обхода массива. Их:

  1. цикл for
  2. цикл while
  3. цикл for-of
  4. map()
  5. forEach()
  6. filter()
  7. reduce()
90 013 1. для шлейфа

Это один из основных методы перебора массива. Цикл for можно использовать для обхода массива, используя длину массива. В цикле for следует упомянуть три условия.

  1. Начальное базовое условие
  2. Конечное условие
  3. Условие повторения (обычно увеличение или уменьшение)

Пример:

2. Цикл while

Цикл while работает аналогично циклу for, но принимает условие и будет выполняться до тех пор, пока данное условие не станет истинным. Если условие становится ложным, цикл while прерывается, и управление переходит к следующему оператору вне цикла. Операторы continue и break можно использовать внутри цикла while.

Пример:

3. Цикл for-of

Цикл for-of похож на цикл for-in в Python, где мы используем «in» в качестве ключевого слова, тогда как в JS «in» заменено на « из». Он используется для перебора массива и может напрямую обращаться к элементам без индексации, поскольку он дает элементы, а не индексирует, как фактический «цикл for».

Пример:

Это можно использовать, когда нам нужно просто получить доступ к элементам и не нужно манипулировать ими, поскольку мы не можем получить доступ к индексу элементов.

4. map()

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

Пример: для работы с массивом

5. forEach()

forEach() также является методом массива и очень похож на функцию map(), тогда как единственное отличие состоит в том, что метод forEach() не вернуть что-либо. Это вернет undefined. Функции, которые могут быть реализованы с помощью метода map(), также могут быть реализованы с помощью forEach(), но для изменения элемента в новом массиве вручную требуются дополнительные усилия.

Пример:

6. filter()

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

Пример: фильтрация нечетных чисел в массиве

7. reduce()

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