#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:
- Создайте обратную карту кода города к названию города,
O(1)
постоянно просматривая время. - Уменьшите
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);