/** * Modern array utilities leveraging ES2024 features */ /** * Group array items by a key using ES2024 Object.groupBy * This is more efficient than manual grouping */ export function groupBy( array: T[], keyFn: (item: T) => K ): Record { // Use native Object.groupBy if available (ES2024) if ('groupBy' in Object) { return (Object as any).groupBy(array, keyFn); } // Fallback polyfill return array.reduce((groups, item) => { const key = keyFn(item); if (!groups[key]) { groups[key] = []; } groups[key].push(item); return groups; }, {} as Record); } /** * Chunk array into smaller arrays of specified size * Uses modern array methods for efficiency */ export function chunk(array: T[], size: number): T[][] { if (size <= 0) return []; const chunks: T[][] = []; for (let i = 0; i < array.length; i += size) { chunks.push(array.slice(i, i + size)); } return chunks; } /** * Get unique items from array with optional key function * Leverages Set for better performance */ export function unique(array: T[]): T[]; export function unique(array: T[], keyFn: (item: T) => K): T[]; export function unique(array: T[], keyFn?: (item: T) => K): T[] { if (!keyFn) { return [...new Set(array)]; } const seen = new Set(); return array.filter(item => { const key = keyFn(item); if (seen.has(key)) { return false; } seen.add(key); return true; }); } /** * Safe array access using ES2024 .at() method * Returns undefined for out-of-bounds access */ export function safeAt(array: T[], index: number): T | undefined { return array.at?.(index) ?? array[index]; } /** * Partition array into two arrays based on predicate */ export function partition( array: T[], predicate: (item: T) => boolean ): [T[], T[]] { const truthy: T[] = []; const falsy: T[] = []; for (const item of array) { if (predicate(item)) { truthy.push(item); } else { falsy.push(item); } } return [truthy, falsy]; } /** * Modern intersection of arrays */ export function intersection(...arrays: T[][]): T[] { if (arrays.length === 0) return []; if (arrays.length === 1) return [...arrays[0]]; const [first, ...rest] = arrays; const sets = rest.map(arr => new Set(arr)); return first.filter(item => sets.every(set => set.has(item))); } /** * Safe array operations that return null on empty arrays */ export const SafeArray = { first: (array: T[]): T | null => array[0] ?? null, last: (array: T[]): T | null => array.at?.(-1) ?? array[array.length - 1] ?? null, random: (array: T[]): T | null => { if (array.length === 0) return null; return array[Math.floor(Math.random() * array.length)]; } } as const;