Saltar al contenido principal

arrayGroupBy

Paquete: @tiendana/utils

Agrupa elementos de un array por el valor de un campo específico, retornando un objeto donde las claves son los valores únicos del campo y los valores son arrays de elementos que comparten esa clave.

Características​

✅ Agrupa por cualquier campo
✅ Soporta campos numéricos y string
✅ Útil para organizar datos
✅ Retorna objeto indexado por valor

Firma​

function arrayGroupBy(
array: any[],
field: string | number
): object

Parámetros​

ParámetroTipoDescripciónRequerido
arrayany[]Array de objetos a agrupar✅
fieldstring | numberCampo por el cual agrupar✅

Retorno​

Tipo: object

Objeto donde:

  • Claves: Valores únicos del campo especificado
  • Valores: Arrays de elementos que tienen esa clave
{
[valorCampo]: [...elementos],
[otroValor]: [...elementos]
}

Ejemplos de Uso​

Agrupar por Categoría​

import { arrayGroupBy } from '@tiendana/utils';

const products = [
{ id: 1, name: 'Laptop', category: 'electronics' },
{ id: 2, name: 'Shirt', category: 'clothing' },
{ id: 3, name: 'Phone', category: 'electronics' },
{ id: 4, name: 'Pants', category: 'clothing' }
];

const grouped = arrayGroupBy(products, 'category');
// {
// electronics: [
// { id: 1, name: 'Laptop', category: 'electronics' },
// { id: 3, name: 'Phone', category: 'electronics' }
// ],
// clothing: [
// { id: 2, name: 'Shirt', category: 'clothing' },
// { id: 4, name: 'Pants', category: 'clothing' }
// ]
// }

Agrupar por Rol de Usuario​

interface User {
id: number;
name: string;
role: 'admin' | 'user' | 'guest';
}

const users: User[] = [
{ id: 1, name: 'Ana', role: 'admin' },
{ id: 2, name: 'Juan', role: 'user' },
{ id: 3, name: 'María', role: 'admin' },
{ id: 4, name: 'Pedro', role: 'guest' }
];

const byRole = arrayGroupBy(users, 'role');
// {
// admin: [Ana, María],
// user: [Juan],
// guest: [Pedro]
// }

// Renderizar por rol
Object.entries(byRole).forEach(([role, users]) => {
console.log(`${role.toUpperCase()}:`);
users.forEach(user => console.log(` - ${user.name}`));
});

Agrupar Pedidos por Estado​

interface Order {
id: string;
status: 'pending' | 'processing' | 'completed' | 'cancelled';
total: number;
}

const orders: Order[] = [
{ id: 'ORD-001', status: 'completed', total: 150 },
{ id: 'ORD-002', status: 'pending', total: 200 },
{ id: 'ORD-003', status: 'completed', total: 300 },
{ id: 'ORD-004', status: 'processing', total: 100 }
];

const byStatus = arrayGroupBy(orders, 'status');

// Calcular totales por estado
const totals = Object.entries(byStatus).map(([status, orders]) => ({
status,
count: orders.length,
total: orders.reduce((sum, order) => sum + order.total, 0)
}));

Agrupar por Fecha​

interface Event {
title: string;
date: string; // '2024-01-15'
}

const events: Event[] = [
{ title: 'Meeting', date: '2024-01-15' },
{ title: 'Call', date: '2024-01-15' },
{ title: 'Workshop', date: '2024-01-16' }
];

const byDate = arrayGroupBy(events, 'date');
// {
// '2024-01-15': [Meeting, Call],
// '2024-01-16': [Workshop]
// }

Agrupar por Valor Numérico​

interface Student {
name: string;
grade: number;
}

const students: Student[] = [
{ name: 'Ana', grade: 10 },
{ name: 'Juan', grade: 9 },
{ name: 'María', grade: 10 },
{ name: 'Pedro', grade: 8 }
];

const byGrade = arrayGroupBy(students, 'grade');
// {
// 10: [Ana, María],
// 9: [Juan],
// 8: [Pedro]
// }

Renderizar Menú Agrupado​

interface MenuItem {
id: string;
label: string;
section: 'main' | 'settings' | 'help';
}

const menuItems: MenuItem[] = [
{ id: '1', label: 'Dashboard', section: 'main' },
{ id: '2', label: 'Profile', section: 'settings' },
{ id: '3', label: 'Users', section: 'main' },
{ id: '4', label: 'FAQ', section: 'help' }
];

const groupedMenu = arrayGroupBy(menuItems, 'section');

// Renderizar en React/Angular
function Menu() {
return (
<nav>
{Object.entries(groupedMenu).map(([section, items]) => (
<div key={section}>
<h3>{section}</h3>
<ul>
{items.map(item => (
<li key={item.id}>{item.label}</li>
))}
</ul>
</div>
))}
</nav>
);
}

Estadísticas por Grupo​

const sales = [
{ product: 'A', region: 'North', amount: 100 },
{ product: 'B', region: 'South', amount: 150 },
{ product: 'A', region: 'North', amount: 200 },
{ product: 'C', region: 'South', amount: 300 }
];

const byRegion = arrayGroupBy(sales, 'region');

const stats = Object.entries(byRegion).map(([region, sales]) => ({
region,
totalSales: sales.reduce((sum, s) => sum + s.amount, 0),
avgSale: sales.reduce((sum, s) => sum + s.amount, 0) / sales.length,
count: sales.length
}));

Casos de Uso Comunes​

  • Organizar datos para mostrar: Agrupar productos por categoría, usuarios por rol
  • Reportes: Agrupar ventas por región, fecha, producto
  • Navegación: Menús agrupados por sección
  • Estadísticas: Calcular agregados por grupo
  • Tablas agrupadas: Mostrar datos con cabeceras de grupo
  • Filtros: Organizar opciones de filtro por tipo

Notas Técnicas​

  • Performance: O(n) - recorre el array una vez
  • Campos inexistentes: Si un elemento no tiene el campo, crea grupo con clave undefined
  • Mutabilidad: No modifica el array original
  • Orden: Preserva el orden de primera aparición dentro de cada grupo
  • Tipo de retorno: object genérico, no tipado estrictamente
  • Claves: Usa el valor del campo directamente como clave del objeto

Limitaciones​

Tipado TypeScript

El retorno es object genérico. Para mejor tipado:

interface GroupedResult<T> {
[key: string]: T[];
}

const grouped: GroupedResult<Product> = arrayGroupBy(products, 'category') as any;

Implementación​

export function arrayGroupBy(array: any[], field: string | number): object {
const array_group_by: any = {};

for (let index = 0; index < array.length; ++index) {
if (array_group_by[array[index][field]] === undefined) {
array_group_by[array[index][field]] = [];
}
array_group_by[array[index][field]].push(array[index]);
}

return array_group_by;
}

Ver También​