javascript - Hvordan kan jeg gruppere et array av objekter etter nøkkel?
Vet noen om en måte (lodash hvis mulig også) å gruppere et array av objekter etter en objektnøkkel og deretter lage et nytt array av objekter basert på gruppering? For eksempel har jeg et array med bilobjekter:
const cars = [
{
'make': 'audi',
'model': 'r8',
'year': '2012'
}, {
'make': 'audi',
'model': 'rs5',
'year': '2013'
}, {
'make': 'ford',
'model': 'mustang',
'year': '2012'
}, {
'make': 'ford',
'model': 'fusion',
'year': '2015'
}, {
'make': 'kia',
'model': 'optima',
'year': '2012'
},
];
Jeg vil lage et nytt array av bilobjekter som er gruppert etter make:
const cars = {
'audi': [
{
'model': 'r8',
'year': '2012'
}, {
'model': 'rs5',
'year': '2013'
},
],
'ford': [
{
'model': 'mustang',
'year': '2012'
}, {
'model': 'fusion',
'year': '2015'
}
],
'kia': [
{
'model': 'optima',
'year': '2012'
}
]
}
Svar #1
I ren Javascript kunne du bruke Array#reduce med et objekt
var cars = [{ make: 'audi', model: 'r8', year: '2012' }, { make: 'audi', model: 'rs5', year: '2013' }, { make: 'ford', model: 'mustang', year: '2012' }, { make: 'ford', model: 'fusion', year: '2015' }, { make: 'kia', model: 'optima', year: '2012' }],
result = cars.reduce(function (r, a) {
r[a.make] = r[a.make] || [];
r[a.make].push(a);
return r;
}, Object.create(null));
console.log(result);.as-console-wrapper { max-height: 100% !important; top: 0; }OPPDATERING 2023
Nå med Object.groupBy. Den tar en iterable og en funksjon for gruppering.
var cars = [{ make: 'audi', model: 'r8', year: '2012' }, { make: 'audi', model: 'rs5', year: '2013' }, { make: 'ford', model: 'mustang', year: '2012' }, { make: 'ford', model: 'fusion', year: '2015' }, { make: 'kia', model: 'optima', year: '2012' }],
result = Object.groupBy(cars, ({ make }) => make);
console.log(result);.as-console-wrapper { max-height: 100% !important; top: 0; }Svar #2
Timos svar er hvordan jeg ville gjort det. Enkel _.groupBy, og tillat noen duplikater i objektene i den grupperte strukturen.
Men OP ba også om at de dupliserte make-nøklene skulle fjernes. Hvis du ønsket å gå hele veien:
var grouped = _.mapValues(_.groupBy(cars, 'make'),
clist => clist.map(car => _.omit(car, 'make')));
console.log(grouped);
Avkastning :
{ audi:
[ { model: 'r8', year: '2012' },
{ model: 'rs5', year: '2013' } ],
ford:
[ { model: 'mustang', year: '2012' },
{ model: 'fusion', year: '2015' } ],
kia:
[ { model: 'optima', year: '2012' } ]
}
Hvis du ønsket å gjøre dette ved å bruke Underscore.js, merk at dens versjon av _.mapValues kalles _.mapObject.
Svar #3
Du leter etter _.groupBy().
Å fjerne egenskapen du grupperer etter fra objektene bør være trivielt hvis det er nødvendig:
const cars = [{
'make': 'audi',
'model': 'r8',
'year': '2012'
}, {
'make': 'audi',
'model': 'rs5',
'year': '2013'
}, {
'make': 'ford',
'model': 'mustang',
'year': '2012'
}, {
'make': 'ford',
'model': 'fusion',
'year': '2015'
}, {
'make': 'kia',
'model': 'optima',
'year': '2012'
}];
const grouped = _.groupBy(cars, car => car.make);
console.log(grouped);<script src='https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js'></script>Svar #4
Det er absolutt ingen grunn til å laste ned et tredjepartsbibliotek for å løse dette enkle problemet, som de ovennevnte løsningene antyder.
Én-linjersversjonen for å gruppere en list av objekter etter en bestemt key i es6:
const groupByKey = (list, key) => list.reduce((hash, obj) => ({...hash, [obj[key]]:( hash[obj[key]] || [] ).concat(obj)}), {})
Den lengre versjonen som filtrerer ut objektene uten key:
function groupByKey(array, key) {
return array
.reduce((hash, obj) => {
if(obj[key] === undefined) return hash;
return Object.assign(hash, { [obj[key]]:( hash[obj[key]] || [] ).concat(obj)})
}, {})
}
var cars = [{'make':'audi','model':'r8','year':'2012'},{'make':'audi','model':'rs5','year':'2013'},{'make':'ford','model':'mustang','year':'2012'},{'make':'ford','model':'fusion','year':'2015'},{'make':'kia','model':'optima','year':'2012'}];
console.log(groupByKey(cars, 'make'))MERK: Det ser ut til at det opprinnelige spørsmålet spør hvordan man grupperer biler etter merke, men utelater merket i hver gruppe. Så det korte svaret, uten tredjepartsbiblioteker, vil se slik ut:
var groupByKey = (list, key) => list.reduce((map, obj) => {
const group = obj[key];
if(map.has(key)) {
map.get(group).push(obj);
} else {
map.set(group, [obj])
}
return map
}, new Map())
var cars = [{'make':'audi','model':'r8','year':'2012'},{'make':'audi','model':'rs5','year':'2013'},{'make':'ford','model':'mustang','year':'2012'},{'make':'ford','model':'fusion','year':'2015'},{'make':'kia','model':'optima','year':'2012'}];
console.log(...groupByKey(cars, 'make', {omitKey:true}))Svar #5
Her er din helt egen groupBy-funksjon som er en generalisering av koden fra: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore
function groupBy(xs, f) {
return xs.reduce((r, v, i, a, k = f(v)) => ((r[k] || (r[k] = [])).push(v), r), {});
}
const cars = [{ make: 'audi', model: 'r8', year: '2012' }, { make: 'audi', model: 'rs5', year: '2013' }, { make: 'ford', model: 'mustang', year: '2012' }, { make: 'ford', model: 'fusion', year: '2015' }, { make: 'kia', model: 'optima', year: '2012' }];
const result = groupBy(cars, (c) => c.make);
console.log(result);Svar #6
Det er også mulig med en enkel for-løkke:
const result = {};
for(const {make, model, year} of cars) {
if(!result[make]) result[make] = [];
result[make].push({ model, year });
}
Svar #7
var cars = [{
make: 'audi',
model: 'r8',
year: '2012'
}, {
make: 'audi',
model: 'rs5',
year: '2013'
}, {
make: 'ford',
model: 'mustang',
year: '2012'
}, {
make: 'ford',
model: 'fusion',
year: '2015'
}, {
make: 'kia',
model: 'optima',
year: '2012'
}].reduce((r, car) => {
const {
model,
year,
make
} = car;
r[make] = [...r[make] || [], {
model,
year
}];
return r;
}, {});
console.log(cars);Svar #8
Jeg ville latt REAL GROUP BY for JS Arrays-eksempelet være nøyaktig det samme som denne oppgaven her
const inputArray = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
var outObject = inputArray.reduce(function(a, e) {
// GROUP BY estimated key (estKey), well, may be a just plain key
// a -- Accumulator result object
// e -- sequentally checked Element, the Element that is tested just at this itaration
// new grouping name may be calculated, but must be based on real value of real field
let estKey = (e['Phase']);
(a[estKey] ? a[estKey] : (a[estKey] = null || [])).push(e);
return a;
}, {});
console.log(outObject);Svar #9
Du kan prøve å endre objektet inne i funksjonen som kalles per iterasjon av _.groupBy-funksjonen. Merk at kildearrayet endrer elementene sine!
var res = _.groupBy(cars,(car)=>{
const makeValue=car.make;
delete car.make;
return makeValue;
})
console.log(res);
console.log(cars);
