Как создавать массивы объектов С Общим значением Реквизита

#javascript #ecmascript-6

Вопрос:

Допустим, у меня есть массив объектов, таких как:

 flattenedObjects = [
  {name: 'Bill', city: 1},
  {name: 'Guillermo', city: 1},
  {name: 'Wilhem', city: 1},
  {name: 'William', city: 1},
  {name: 'Nick', city: 2},
  {name: 'Nicolas', city: 2},
  {name: 'Nicholas', city: 2},
  {name: 'Rick', city: 3}
]
 

Я хочу создать отдельные массивы объектов, сгруппированных по «городу». В коде я также деконструирую каждый объект так, чтобы конечный результат был:

 boston = ['Bill', 'Guillermo', 'Wilhelm', 'William']
miami = ['Nick', 'Nickolas', 'Nicholas']
london = ['Rick']
 

У меня возникли трудности с созданием сгруппированного массива объектов.

Я могу сделать это с помощью одного-единственного объекта, как такового:

 let boston = flattenedObjects.filter(function (obj) {
  return obj.city == 1;
});
 

Я думал о том, чтобы выполнить итерацию по объекту и динамически фильтровать, вот так:

 let cities = {
  boston: 1,
  miami: 2,
  london: 3
}
 

А затем попробовать что-то вроде:

 let newObj = flattenedObjects.filter(function (x) {
  let obj = {};
  Object.entries(cities).forEach(([key, value]) => {
    obj["name"] = `${key}`;
    obj["city"] = x.city == `${value}`;
    return obj;
  });
});
 

Это не утешает то, что ожидается. Это просто массив объектов, очень похожих на «объект» выше.

Комментарии:

1. Это flattenedObjects не массив. Вы имели в виду, flattenedObjects = [ {name: 'Bill', city: 1}, /* ... */ ] ?

2. flattenedObjects является объектом, поэтому вы не можете вызывать методы массива для него. filter Функция также не возвращает значение true/false для того, какие значения должны быть возвращены в любом результирующем массиве. В вашей структуре данных город-это номер, но вы ожидаете, что он будет сгруппирован по названиям городов, есть ли какой-то другой соответствующий код, которым вы не поделились?

3. Array.prototype.filter() Обратный вызов @DrewReese принимает истинные/ложные значения в качестве возвращаемого типа (то есть любое значение), хотя семантически правильнее возвращать логическое значение.

4. Да, извините, «flattenedObjects» — это массив, и я могу отфильтровать его (как показано ниже в примере). Это была орфографическая ошибка.

5. @j1mbl3s Я понимаю, как работает фильтрация массивов, код операции возвращает неопределенное значение для каждого элемента, так как существует неявное возвращение void.

Ответ №1:

 let flattenedObjects = [
  {name: 'Bill',city: 1},
  {name: 'Guillermo',city: 1},
  {name: 'Wilhem',city: 1},
  {name: 'William',city: 1},
  {name: 'Nick',city: 2},
  {name: 'Nicolas',city: 2},
  {name: 'Nicholas',city: 2},
  {name: 'Rick',city: 3}
];

let cities = {
  boston: 1,
  miami: 2,
  london: 3
}

let data = {}
for (const [key, value] of Object.entries(cities)) {
  data[key] = flattenedObjects.filter(p => p.city === value).map(e => e.name);
}
console.log(data) 

Ответ №2:

  1. Создайте обратную карту кода города к названию города, O(1) постоянно просматривая время.
  2. Уменьшите flattenedObjects массив в объект, используя название города в качестве ключа, и создайте массив для имен, O(n) линейный доступ.
 const flattenedObjects = [
  { name: "Bill", city: 1 },
  { name: "Guillermo", city: 1 },
  { name: "Wilhem", city: 1 },
  { name: "William", city: 1 },
  { name: "Nick", city: 2 },
  { name: "Nicolas", city: 2 },
  { name: "Nicholas", city: 2 },
  { name: "Rick", city: 3 }
];

const cities = {
  boston: 1,
  miami: 2,
  london: 3
};

const citiesByCode = Object.fromEntries(
  Object.entries(cities).map(([city, code]) => [code, city])
);

const groupedResult = flattenedObjects.reduce((groups, current) => {
  const cityCode = citiesByCode[current.city];
  if (!groups[cityCode]) groups[cityCode] = [];
  groups[cityCode].push(current.name);
  return groups;
}, {});

console.log(groupedResult); 

Ответ №3:

Вы можете использовать reduce инструкцию для сокращения flattenedObjects массива в один объект в нужном вам формате.

 const flattenedObjects = [
  {name: 'Bill', city: 1},
  {name: 'Guillermo', city: 1},
  {name: 'Wilhem', city: 1},
  {name: 'William', city: 1},
  {name: 'Nick', city: 2},
  {name: 'Nicolas', city: 2},
  {name: 'Nicholas', city: 2},
  {name: 'Rick', city: 3},
];
// the keys are the city number rather than city name
const cities = {
  1: 'boston',
  2: 'miami',
  3: 'london',
};

const obj = flattenedObjects.reduce((o, flattenedObject) => {
  const cityName = cities[flattenedObject.city];
  if (o[cityName] === undefined) {
    o[cityName] = [];
  }
  o[cityName].push(flattenedObject.name);
  return o;
}, {});
console.log(obj);