javascript - dinamico - Cómo agrupar una matriz de objetos por clave
matriz javascript (18)
Aquí está su propia función
groupBy
, que es una generalización del código de:
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);
¿Alguien sabe de una manera (lodash si es posible también) de agrupar una matriz de objetos por una clave de objeto y luego crear una nueva matriz de objetos basada en la agrupación? Por ejemplo, tengo una variedad de objetos de automóviles:
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''
},
];
Quiero hacer una nueva matriz de objetos de automóviles que se agrupen por
make
:
var cars = {
''audi'': [
{
''model'': ''r8'',
''year'': ''2012''
}, {
''model'': ''rs5'',
''year'': ''2013''
},
],
''ford'': [
{
''model'': ''mustang'',
''year'': ''2012''
}, {
''model'': ''fusion'',
''year'': ''2015''
}
],
''kia'': [
{
''model'': ''optima'',
''year'': ''2012''
}
]
}
Con lodash / fp puede crear una función con
_.flow()
que primero agrupa por una tecla, y luego
_.flow()
cada grupo y omite una tecla de cada elemento:
const { flow, groupBy, mapValues, map, omit } = _;
const groupAndOmitBy = key => flow(
groupBy(key),
mapValues(map(omit(key)))
);
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 groupAndOmitMake = groupAndOmitBy(''make'');
const result = groupAndOmitMake(cars);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src=''https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)''></script>
Cree un método que pueda reutilizarse
Array.prototype.groupBy = function(prop) {
return this.reduce(function(groups, item) {
const val = item[prop]
groups[val] = groups[val] || []
groups[val].push(item)
return groups
}, {})
};
A continuación, puede agrupar por cualquier criterio
const groupByMake = cars.groupBy(''make'');
console.log(groupByMake);
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''
},
];
//re-usable method
Array.prototype.groupBy = function(prop) {
return this.reduce(function(groups, item) {
const val = item[prop]
groups[val] = groups[val] || []
groups[val].push(item)
return groups
}, {})
};
// initiate your groupBy. Notice the recordset Cars and the field Make....
const groupByMake = cars.groupBy(''make'');
console.log(groupByMake);
//At this point we have objects. You can use Object.keys to return an array
Dejaría
REAL GROUP BY
para el ejemplo de JS Arrays exactamente la misma tarea
here
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);
Да здравствуют высокие показатели мастерства программистов во имя процветания всего человечества! Ура, товарищи!
En Javascript simple, puede usar
Array#reduce
con un objeto
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; }
La versión corta para agrupar una matriz de objetos por una determinada clave en es6:
result = array.reduce((h, obj) => Object.assign(h, { [obj.key]:( h[obj.key] || [] ).concat(obj) }), {})
La versión más larga:
result = array.reduce(function(h, obj) {
h[obj.key] = (h[obj.key] || []).concat(obj);
return h;
}, {})
Parece que la pregunta original pregunta cómo agrupar los automóviles por marca, pero omita la marca en cada grupo. Entonces la respuesta se vería así:
result = cars.reduce((h, {model,year,make}) => {
return Object.assign(h, { [make]:( h[make] || [] ).concat({model,year})})
}, {})
Me gustó la respuesta @metakunfu, pero no proporciona exactamente la salida esperada. Aquí hay una actualización que elimina "make" en la carga útil final de JSON.
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((h, car) => Object.assign(h, { [car.make]:( h[car.make] || [] ).concat({model: car.model, year: car.year}) }), {})
console.log(JSON.stringify(result));
Salida:
{
"audi":[
{
"model":"r8",
"year":"2012"
},
{
"model":"rs5",
"year":"2013"
}
],
"ford":[
{
"model":"mustang",
"year":"2012"
},
{
"model":"fusion",
"year":"2015"
}
],
"kia":[
{
"model":"optima",
"year":"2012"
}
]
}
Para casos donde la clave puede ser nula y queremos agruparlos como otros
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''},
{''make'':''kia'',''model'':''optima'',''year'':''2033''},
{''make'':null,''model'':''zen'',''year'':''2012''},
{''make'':null,''model'':''blue'',''year'':''2017''},
];
result = cars.reduce(function (r, a) {
key = a.make || ''others'';
r[key] = r[key] || [];
r[key].push(a);
return r;
}, Object.create(null));
Puede intentar modificar el objeto dentro de la función llamada por iteración por _.groupBy func. ¡Observe que la matriz fuente cambia sus elementos!
var res = _.groupBy(cars,(car)=>{
const makeValue=car.make;
delete car.make;
return makeValue;
})
console.log(res);
console.log(cars);
Sobre la base de la answer de @Jonas_Wilms si no desea escribir en todos sus campos:
var result = {};
for ( let { first_field, ...fields } of your_data )
{
result[first_field] = result[first_field] || [];
result[first_field].push({ ...fields });
}
No hice ningún punto de referencia, pero creo que usar un bucle for también sería más eficiente que cualquier cosa sugerida en esta respuesta .
Solo prueba este, me funciona bien.
let grouped = _.groupBy(cars, ''make'');
También es posible con un bucle
for
simple:
const result = {};
for(const {make, model, year} of cars) {
if(!result[make]) result[make] = [];
result[make].push({ model, year });
}
También puede hacer uso del método
array#forEach()
esta manera:
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'' }];
let newcars = {}
cars.forEach(car => {
newcars[car.make] ? // check if that array exists or not in newcars object
newcars[car.make].push({model: car.model, year: car.year}) // just push
: (newcars[car.make] = [], newcars[car.make].push({model: car.model, year: car.year})) // create a new array and push
})
console.log(newcars);
La respuesta de Timo
es cómo lo haría.
Simple
_.groupBy
, y permite algunas duplicaciones en los objetos en la estructura agrupada.
Sin embargo, el OP también solicitó la eliminación de las claves duplicadas. Si quisieras ir hasta el final:
var grouped = _.mapValues(_.groupBy(cars, ''make''),
clist => clist.map(car => _.omit(car, ''make'')));
console.log(grouped);
Rendimientos:
{ audi:
[ { model: ''r8'', year: ''2012'' },
{ model: ''rs5'', year: ''2013'' } ],
ford:
[ { model: ''mustang'', year: ''2012'' },
{ model: ''fusion'', year: ''2015'' } ],
kia: [ { model: ''optima'', year: ''2012'' } ] }
Si desea hacer esto usando Underscore.js, tenga en cuenta que su versión de
_.mapValues
se llama
_.mapObject
.
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, a) => {
const {
model,
year
} = a;
r[a.make] = [...r[a.make] || [], {
model,
year
}];
return r;
}, {});
console.log(cars);
Estás buscando
_.groupBy()
.
Eliminar la propiedad por la que está agrupando los objetos debería ser trivial si es necesario:
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''},];
var grouped = _.groupBy(cars, function(car) {
return car.make;
});
console.log(grouped);
<script src=''https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js''></script>
Como beneficio adicional, obtienes una sintaxis aún mejor con las funciones de flecha ES6:
const grouped = _.groupBy(cars, car => car.make);
const reGroup = (list, key) => {
const newGroup = {};
list.forEach(item => {
const newItem = Object.assign({}, item);
delete newItem[key];
newGroup[item[key]] = newGroup[item[key]] || [];
newGroup[item[key]].push(newItem);
});
return newGroup;
};
const animals = [
{
type: ''dog'',
breed: ''puddle''
},
{
type: ''dog'',
breed: ''labradoodle''
},
{
type: ''cat'',
breed: ''siamese''
},
{
type: ''dog'',
breed: ''french bulldog''
},
{
type: ''cat'',
breed: ''mud''
}
];
console.log(reGroup(animals, ''type''));
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''
},
];
console.log(reGroup(cars, ''make''));
function groupBy(data, property) {
return data.reduce((acc, obj) => {
const key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
groupBy(people, ''age'');