Módulo 00 // Unidad 06

Transformar colecciones con métodos de array

Recorrer, filtrar, transformar y resumir listas sin escribir bucles a mano

Unidad para alumnos del curso

Comprobando tu sesión…

Inicia sesión con la cuenta de Google con la que estás matriculado para ver esta unidad.

Esa cuenta no tiene acceso a este curso. Prueba con otra.

No se ha podido cargar el inicio de sesión de Google. Comprueba la conexión o si algún bloqueador lo impide, y recarga la página.

Casi todo lo que harás con datos en el cliente es trabajar con listas: los productos que llegan de una API, las tareas de una aplicación, las filas de una tabla. Podrías recorrerlas siempre con for, pero los arrays traen métodos que dicen qué quieres obtener en lugar de cómo recorrer. Todos se basan en lo que ya sabes: reciben una función como argumento.

1 // Recorrer y buscar

Todos los métodos de esta unidad reciben un callback que se llama una vez por elemento, con tres argumentos: el elemento, su índice y el array completo. Casi siempre sólo usarás el primero.

const alumnos = [
  { nombre: 'Ana', nota: 8, curso: '2DAW' },
  { nombre: 'Luis', nota: 4, curso: '2DAW' },
  { nombre: 'Eva', nota: 9, curso: '2DAM' },
];

alumnos.forEach(a => console.log(a.nombre));       // recorre, no devuelve nada

alumnos.find(a => a.nota < 5);                     // { nombre: 'Luis', ... }
alumnos.findIndex(a => a.nombre === 'Eva');        // 2
alumnos.some(a => a.nota < 5);                     // true: al menos uno
alumnos.every(a => a.nota >= 5);                   // false: no todos

find devuelve el primer elemento que cumple la condición, o undefined si ninguno la cumple. some y every responden sí o no y dejan de recorrer en cuanto conocen la respuesta.

Para recorrer también existe for...of, que es la opción adecuada cuando necesitas salir antes con break o usar await dentro del bucle:

for (const alumno of alumnos) {
  if (alumno.nota < 5) break;
  console.log(alumno.nombre);
}

2 // Filtrar, transformar y resumir

Los tres métodos más importantes devuelven un resultado nuevo sin tocar el array original:

Método El callback devuelve El método devuelve
filter true o false: ¿se queda este elemento? Array con los que pasan
map El valor transformado Array del mismo tamaño
reduce El acumulado hasta ahora Un único valor
const aprobados = alumnos.filter(a => a.nota >= 5);
// [{ nombre: 'Ana', ... }, { nombre: 'Eva', ... }]

const nombres = alumnos.map(a => a.nombre);
// ['Ana', 'Luis', 'Eva']

const sumaNotas = alumnos.reduce((acumulado, a) => acumulado + a.nota, 0);
// 21

reduce es el que más cuesta al principio. Léelo así: empieza con el valor inicial (0), y en cada vuelta el callback recibe lo acumulado y el elemento actual, y devuelve el nuevo acumulado. En la primera vuelta devuelve 0 + 8; en la segunda, 8 + 4; en la tercera, 12 + 9.

Elige el método por lo que quieres obtener: un subconjunto, filter; una lista transformada, map; un solo elemento, find; un único valor calculado a partir de todos, reduce; nada, sólo efectos, forEach.

3 // Métodos que modifican el array

No todos los métodos son igual de respetuosos. Algunos modifican el array sobre el que se llaman, y eso importa por lo que viste en la unidad de referencias: si ese array se usa en otra parte, también cambia allí.

Modifican el original No lo modifican
push, pop, shift, unshift map, filter, reduce, find
splice slice, concat
sort, reverse toSorted, toReversed
fill toSpliced, with

Las versiones con to (toSorted, toReversed, toSpliced) y with son recientes y hacen lo mismo que sus equivalentes, pero devolviendo un array nuevo.

sort() sin argumentos ordena como texto, incluso si todos los elementos son números: [10, 9, 1].sort() da [1, 10, 9]. Pasa siempre una función de comparación: (a, b) => a - b para orden ascendente, (a, b) => b - a para descendente, o (a, b) => a.nombre.localeCompare(b.nombre) para textos.

4 // Encadenar métodos

Como filter y map devuelven arrays, puedes llamar al siguiente método directamente sobre el resultado. Así, un procesamiento de varios pasos se lee de arriba abajo:

UNA CADENA FILTER → MAP → REDUCE productos 10 € · en stock 25 € · agotado 5 € · en stock 40 € · en stock .filter(enStock) 10 5 40 .map(conIva) 12.10 6.05 48.40 .reduce(sumar, 0) 66.55 4 elementos no se modifica 3 elementos decide cuáles pasan 3 elementos transforma cada uno 1 valor combina todos
Mira cómo cambia el número de elementos en cada paso: filter reduce la lista, map mantiene su tamaño y reduce la convierte en un único valor.

Una tienda tiene esta lista y quiere mostrar el total con IVA de los productos disponibles:

const productos = [
  { nombre: 'Cable', precio: 10, stock: 3 },
  { nombre: 'Ratón', precio: 25, stock: 0 },
  { nombre: 'Funda', precio: 5, stock: 12 },
  { nombre: 'Teclado', precio: 40, stock: 1 },
];
  1. Quedarse con los disponibles: .filter(p => p.stock > 0) deja Cable, Funda y Teclado.
  2. Calcular el precio con IVA de cada uno: .map(p => p.precio * 1.21) da [12.1, 6.05, 48.4].
  3. Sumarlos: .reduce((total, precio) => total + precio, 0) da 66.55.
  4. Redondear para mostrarlo: con precios en coma flotante no hay garantía de que el resultado salga exacto (recuerda 0.1 + 0.2), así que .toFixed(2) lo convierte en el texto '66.55' con dos decimales fijos.
const total = productos
  .filter(p => p.stock > 0)
  .map(p => p.precio * 1.21)
  .reduce((suma, precio) => suma + precio, 0)
  .toFixed(2);
El total es 66.55 €, y el array productos sigue intacto con sus cuatro elementos. Cada línea de la cadena responde a una pregunta: cuáles, qué valor de cada uno y cómo se combinan.

5 // Para practicar

Resuelve cada ejercicio primero con un bucle y después con el método de array adecuado. Cada ejercicio trae el enunciado en los comentarios del código.

Suma, máximo, mínimo y mediatraining-daw-sv/modulo-00/06-metodos-de-array/01_math_arrayInsertar sin duplicar ni modificartraining-daw-sv/modulo-00/06-metodos-de-array/02_insert_if_not_existsPilotos con map, filter y reducetraining-daw-sv/modulo-00/06-metodos-de-array/03_iterators

Autoevaluación

¿Por qué const nombres = alumnos.forEach(a => a.nombre) deja nombres en undefined, y qué método habría que usar?
forEach sólo recorre; no construye nada. Ejecuta la función para cada elemento y siempre devuelve undefined, ignorando lo que devuelva el callback. Para obtener un array nuevo con un valor por elemento se usa map.
[10, 9, 1].sort() devuelve [1, 10, 9]. ¿Qué está haciendo sort y cómo se corrige?
Sin función de comparación, sort ordena como texto. Convierte cada elemento en cadena y compara carácter a carácter, y '10' va antes que '9' porque '1' va antes que '9'. Con (a, b) => a - b se ordena numéricamente.
En un reduce para sumar precios, ¿qué papel tienen el acumulador y el valor inicial?
El acumulador es el resultado parcial que viaja de una vuelta a la siguiente. En cada llamada, el callback recibe lo acumulado y el elemento actual, y devuelve el nuevo acumulado. El valor inicial es el acumulado de la primera vuelta; sin él, reduce usa el primer elemento y falla con arrays vacíos.