Преобразование массива с помощью сокращения (свойство не определено)

Я хочу преобразовать массив в перегруппировку всех городов для одной страны. У меня есть массив объектов

locations = [
{
cities: ["Paris"]
country: "France"
},
{
cities: ["Marseille"]
country: "France"
},
{
cities: ["Kiev"]
country: "Ukraine"
},
{
cities: ["Odessa"]
country: "Ukraine"
}
...

И я хочу это:

locations = [
{
cities: ["Paris", "Marseille"]
country: "France"
},
{
cities: ["Kiev, Odessa"]
country: "Ukraine"
},
...

Итак, мое мышление таково:

locations.reduce((prev, curr) => {
    if (prev.country === curr.country) {
      prev.cities.push(curr.cities[0])
      // and delete curr Object
    }
  })

Для первой пары равных стран curr.cities[0] помещается в prev.cities, но не для следующей итерации: TypeError: невозможно прочитать свойство «страна» неопределенного

[![console.info(locations) - TypeError: Невозможно прочитать свойство 'country' of undefined][1]][1]

Можете ли вы поделиться значениями в каждом массиве cities и результатом, который вы пытаетесь получить после преобразования объекта?

Mureinik 19.12.2020 21:42

вы не возвращаете prev из внутренней функции сокращения. поэтому в следующей итерации prev не существует.

Robert 19.12.2020 21:44
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
85
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

При использовании уменьшить вам нужно вернуть prev для использования в следующих итерациях, а также инициализировать его на {}. Кроме того, вам нужно позаботиться о первоначальном добавлении каждой страны, в которой должен храниться объект с массивом cities:

const locations = [
  { country: "France", cities: ['city1','city2'] },
  { country: "France", cities: ['city3','city4'] },
  { country: "Ukraine", cities: ['city5'] },
  { country: "Ukraine", cities: ['city6'] }
];

const res = Object.values(locations.reduce((prev, curr) => {
  const { country, cities = [] } = curr;
  const [city] = cities;
  if (prev[country] && city) {
    prev[country].cities.push(city);
  } else {
    prev[country] = { country, cities: city ? [city] : [] };
  }
  return prev;
}, {}));

console.info(res);

Я думаю, что для достижения желаемого формата вывода вы можете сделать что-то вроде этого:

locations = [
  { cities: ["Paris"], country: "France" },
  { cities: ["Marseille"], country: "France" },
  { cities: ["Kiev"], country: "Ukraine" },
  { cities: ["Odesa"], country: "Ukraine" }
];

var grouped = Object.entries(
  locations.reduce((a, {country, cities}) => ({
    ...a, [country]: [...(a[country] || []), ...cities]
  }), {})
).map(([country, cities]) => ({ country: country, cities: cities }), []);
  
console.info(grouped);

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

let locations = [{cities: ["Paris"],country: "France"},{cities: ["Marseille"],country: "France"},{cities: ["Kiev"],country: "Ukraine"},{cities: ["Odesa"], country: "Ukraine"}];

let map = new Map(locations.map(({country}) => [country, {country, cities: []}]));
for (let loc of locations) map.get(loc.country).cities.push(...loc.cities);
let res = Array.from(map.values());

console.info(res);

Другие вопросы по теме