angular - Equivalente en Javascript a C# LINQ GroupBy
Esta es una pregunta de seguimiento a la siguiente pregunta:
Equivalente en Javascript a C# LINQ Select
Estamos usando Angular 2 + TypeScript:
Tengo un arreglo de objetos. Cada objeto en el arreglo incluye una propiedad llamada 'StudentType'.
Necesito ejecutar una consulta al estilo LINQ en C# que extraiga una lista de StudentType en el arreglo y el número de miembros del arreglo con ese tipo particular.
Aunque puedo hacer un bucle al estilo antiguo y hacer esto, me pregunto si hay una mejor manera de hacerlo, como lo que ofrece C# LINQ GroupBy.
Dado que estamos usando Angular 2, los líderes del proyecto no permiten el uso de JQuery.
Respuesta #1
Solo inventé algunos valores de studentType para pruebas, pero puedes usar Array.prototype.reduce() para iterar sobre cada elemento del array de entrada y agregar o manipular propiedades de un objeto acumulador.
let arr = [{
studentType: 'freshman'
},
{
studentType: 'senior'
},
{
studentType: 'sophomore'
},
{
studentType: 'freshman'
},
{
studentType: 'junior'
},
{
studentType: 'senior'
},
{
studentType: 'sophomore'
},
{
studentType: 'freshman'
},
{
studentType: 'sophomore'
},
{
studentType: 'freshman'
}
];
let result = arr.reduce((prev, curr) => {
isNaN(prev[curr.studentType]) ? prev[curr.studentType] = 1 : prev[curr.studentType]++;
return prev;
}, {});
console.log(result);Respuesta #2
Creé una función groupBy en TypeScript.
export interface Group {
key: any;
items: any[];
}
export interface GroupBy {
keys: string[];
thenby?: GroupBy;
}
export const groupBy = (array: any[], grouping: GroupBy): Group[] => {
const keys = grouping.keys;
const groups = array.reduce((groups, item) => {
const group = groups.find(g => keys.every(key => item[key] === g.key[key]));
const data = Object.getOwnPropertyNames(item)
.filter(prop => !keys.find(key => key === prop))
.reduce((o, key) => ({ ...o, [key]: item[key] }), {});
return group
? groups.map(g => (g === group ? { ...g, items: [...g.items, data] } : g))
: [
...groups,
{
key: keys.reduce((o, key) => ({ ...o, [key]: item[key] }), {}),
items: [data]
}
];
}, []);
return grouping.thenby ? groups.map(g => ({ ...g, items: groupBy(g.items, grouping.thenby) })) : groups;
};
Hice una demostración de ello en StackBlitz en
https://stackblitz.com/edit/typescript-ezydzv
