Saltar al contenido principal
04Arrays

Transformar Arrays

Clase 6 de 88 min de lectura

Ya sabes crear arrays, modificarlos y buscar en ellos. Falta lo que más vas a usar en el día a día: crear arrays nuevos a partir de los que ya tienes. Quedarte solo con algunos elementos, convertir cada uno en otra cosa o resumirlos todos en un único valor.

Para eso hay tres métodos que conviene conocer muy bien: filter, map y reduce.

filter: Un nuevo Array con los elementos que cumplan una condición#

filter funciona como un colador. Le pasas una función, la ejecuta con cada elemento y crea un array nuevo solo con los elementos para los que devuelve true.

Por ejemplo, para quedarte con los números pares:

const numbers = [1, 2, 3, 4, 5, 6, 7]const evenNumbers = numbers.filter(function (number) {  return number % 2 === 0})console.log(evenNumbers) // -> [2, 4, 6]

Los impares devuelven false y se quedan fuera. El array numbers sigue intacto.

Sirve con cualquier condición. Aquí nos quedamos con las cadenas de texto que tienen la letra a:

const strings = ['hola', 'adiós', 'casa', 'coche', 'perro', 'gato']// en las cadenas de texto podemos usar el método `includes`// para saber si una cadena contiene otra:const stringsWithA = strings.filter(string => string.includes('a'))console.log(stringsWithA) // -> ['hola', 'adiós', 'casa', 'gato']

map: Un nuevo Array con los elementos transformados#

Si filter decide quién se queda, map cambia a todos. Crea un array de la misma longitud que el original, donde cada elemento es el resultado de pasar el original por tu función.

La función recibe cada elemento y tiene que devolver el elemento ya transformado. Por ejemplo, el doble de cada número:

const numbers = [1, 2, 3]const doubleNumbers = numbers.map((number) => {  return number * 2})console.log(doubleNumbers) // -> [2, 4, 6]

Entran tres números y salen tres números. Lo que devuelves no tiene por qué ser del mismo tipo que lo que recibes: aquí entran cadenas de texto y sale la longitud de cada una.

const strings = ['hola', 'javascript', 'midu', 'programación']const stringsLength = strings.map((string) => string.length)console.log(stringsLength) // -> [4, 10, 4, 12]

map + filter: Un nuevo Array con los elementos transformados y filtrados#

¿Y si quieres transformar y filtrar a la vez? Como map devuelve un array, puedes llamar a filter directamente sobre ese resultado, sin guardarlo antes en una variable. A esto se le llama encadenar métodos.

Imagina que quieres el doble de cada número y quedarte solo con los resultados mayores que 5. Lee los comentarios para ver qué sale de cada paso:

const numbers = [1, 2, 3, 4, 5, 6, 7]const numsGreaterThanFive = numbers  .map(number => number * 2) // [2, 4, 6, 8, 10, 12, 14]  .filter(number => number > 5) // [6, 8, 10, 12, 14]console.log(numsGreaterThanFive) // -> [6, 8, 10, 12, 14]

El orden lo decides tú. También puedes filtrar primero y transformar después, por ejemplo quedándote con los pares para luego multiplicarlos por 2:

const numbers = [1, 2, 3, 4, 5, 6, 7]const doubleEvenNumbers = numbers  .filter(number => number % 2 === 0) // [2, 4, 6]  .map(number => number * 2) // [4, 8, 12]console.log(doubleEvenNumbers) // -> [4, 8, 12]

reduce: Un único valor a partir de un array#

reduce es el más complejo de los tres, así que vamos despacio. Su trabajo es crear un único valor a partir de un array: una suma, un total, lo que necesites.

Recibe dos parámetros: una función que se ejecuta por cada elemento y un valor inicial, opcional, que es el punto de partida sobre el que se va acumulando.

Esa función, a su vez, recibe estos parámetros:

  • El acumulador: el valor que se va acumulando en cada iteración.
  • El elemento actual: el elemento del array que se está iterando en ese momento.
  • El índice: la posición del elemento actual en el array.

Y debe devolver el valor que quieres acumular para la siguiente iteración.

El caso de uso más típico es sumar todos los elementos de un array:

const numbers = [1, 2, 3]const sum = numbers.reduce((accumulator, currentNumber) => {  return accumulator + currentNumber}, 0) // <- el 0 es el valor inicialconsole.log(sum) // -> 6

Vale, pero ¿qué pasa por dentro? Vamos vuelta a vuelta:

  1. El acumulador vale 0, porque es el valor inicial, y el elemento actual vale 1. Devolvemos 0 + 1 = 1.
  2. El acumulador vale 1, lo que devolvimos en la vuelta anterior, y el elemento actual vale 2. Devolvemos 1 + 2 = 3.
  3. El acumulador vale 3 y el elemento actual vale 3. Devolvemos 3 + 3 = 6.

No quedan más elementos, así que el valor final de sum es 6.

Y así se combinan los tres métodos, uno detrás de otro, para pasar de un array a un único resultado:

Infografía
De un array a un resultado: map, filter y reduce
6.Segunda vuelta: 6 + 8 = 14. No quedan elementos, así que el resultado final es 14.
Paso 6 de 6

¿Recuerdas el encadenamiento de map y filter? Cada método crea un array intermedio. Con reduce puedes ahorrártelo y hacerlo todo en una sola pasada. Por ejemplo, para doblar los números pares y quedarte solo con los mayores de 5:

const numbers = [1, 2, 3, 4, 5, 6, 7]const doubleEvenNumbers = numbers.reduce((accumulator, currentNumber) => {  const isEven = currentNumber % 2 === 0  const doubled = currentNumber * 2  const isGreaterThanFive = doubled > 5  // si es par y mayor que 5, lo añadimos al array  if (isEven && isGreaterThanFive) {    // para ello devolvemos un nuevo array con el valor actual    return accumulator.concat(doubled)  } else {    // si no, devolvemos lo que ya teníamos    return accumulator  }}, []) // <- el array vacío es el valor inicialconsole.log(doubleEvenNumbers) // -> [8, 12]

Esta vez el valor inicial es un array vacío. En cada vuelta, si el número nos interesa lo añadimos al acumulador; si no, lo descartamos devolviendo el acumulador tal cual estaba.

En resumen

  • filter crea un array nuevo solo con los elementos que cumplen una condición.
  • map crea un array nuevo de la misma longitud con cada elemento transformado.
  • Como ambos devuelven un array, se pueden encadenar: .map(...).filter(...).
  • reduce convierte un array en un único valor, acumulando el resultado vuelta a vuelta.
  • Ninguno de los tres modifica el array original.