Métodos de iteradores

Utilizando ayudantes de iteradores


Existen una serie de métodos que podemos utilizar sobre los iteradores que explicamos en el tema anterior. Estos métodos son unas funciones de ayuda para iteradores que nos permiten trabajar con conjuntos de datos de una forma cómoda, funcional y muy práctica.

Ayudante de iteradores

En primer lugar, vamos a analizar estos tres métodos completamente nuevos, que aparecen recientemente y podemos utilizar con los iteradores que tengamos en nuestro código:

Ayudante de iteradorDescripción
.take(limit)Devuelve un iterador con los elementos desde 0 hasta el límite indicado.
.drop(limit)Devuelve un iterador con los elementos a partir del límite indicado.
.toArray()Devuelve un array con los valores del iterador hasta el final.

Veamos algunos ejemplos para entender como funcionan estos interesantes métodos. Observa que partimos de un que contiene 10 con los números de forma textual:

const data = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"];

const iterator = data
  .values()
  .drop(3)
  .take(2);   // Array iterator {}

Mediante el método .values() que vimos en el tema anterior, obtenemos un iterador del , y luego utilizamos alguno de nuestros métodos de ayuda a los iteradores:

  • 1️⃣ drop(3) Descarta los 3 primeros elementos
  • 2️⃣ take(2) Toma los 2 siguientes elementos y descarta el resto

Entonces, nos devuelve un iterador que se guardará en la constante iterator. Ahora, como todo iterador, podemos ejecutar el método .next() para ir obteniendo los valores, que como debería ser, son los valores "Four" y "Five":

// Manual
iterator.next();    // { value: "Four", done: false }
iterator.next();    // { value: "Five", done: false }
iterator.next();    // { value: undefined, done: true }

// Automática
[...iterator]       // ["Four", "Five"]

También podemos utilizar el método .toArray() para convertirlo en un directamente. En el siguiente ejemplo, descartamos los 5 primeros elementos y nos quedamos con el resto hasta el final, conviertiéndolo en un :

data
  .values()
  .drop(5)
  .toArray();   // ['Six', 'Seven', 'Eight', 'Nine', 'Ten']

O En este siguiente ejemplo, donde:

  • 1️⃣ Descartamos los 3 primeros elementos
  • 2️⃣ Tomamos los 4 siguientes elementos y descartamos el resto
  • 3️⃣ Lo convertimos a un array
data
  .values()
  .drop(3)
  .take(4)
  .toArray();   // ['Four', 'Five', 'Six', 'Seven']

Como puedes ver, una forma funcional de trabajar, bastante cómoda y práctica.

Usando generadores

Otra combinación de funcionalidades de Javascript que puede resultar interesante es combinar las funciones generadoras con los iteradores.

Observa el siguiente ejemplo, donde creamos una función generadora que genera números enteros indefinidamente. Esta función tiene un bucle infinito, sin embargo, es una función generadora y tiene un yield que suspende la función hasta que se reanude, que incrementará el número y volverá a suspenderse:

function* generator() {
    let i = 0;
    while (true) {
      yield i;
      i += 1;
    }
}

Esta función generadora simplemente nos va devolviendo en cada iteración un número entero, empezando en el 0 e incrementándolo en uno cada vez que se reanuda. Podemos utilizar dicha función como una generadora de arrays numéricos que gestionaremos mediante métodos para quedarnos con nuestro deseado.

Por ejemplo:

  • 1️⃣ Ejecutamos la función generadora. Como tiene función .next(), se puede usar como iterador.
  • 2️⃣ Con drop(25) descartamos los 25 primeros elementos.
  • 3️⃣ Con take(5) nos quedamos con los 5 siguientes y descartamos el resto.
  • 4️⃣ Convertimos a con toArray().
generator()
  .drop(25)
  .take(5)
  .toArray();   // [25, 26, 27, 28, 29]

Otro ejemplo:

  • 1️⃣ Generamos números con la función generadora.
  • 2️⃣ Descartamos el primer número, es decir, el 0.
  • 3️⃣ Tomamos los 100 siguientes, es decir, del 1 al 100.
  • 4️⃣ Filtramos los que son múltiplos de 10: 10, 20, 30, etc...
  • 5️⃣ Convertimos a .
generator()
  .drop(1)
  .take(100)
  .filter(n => n % 10 === 0)
  .toArray();   // [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Equivalencia con Array functions

Como habrás visto en el último ejemplo anterior, hemos utilizado .filter(), ya que los iteradores también tienen algunos de los métodos de Array o Array functions, disponibles para utilizarlos en los iteradores:

Ayudante de iteradorDescripciónEquivalencia
Iterator.from(obj)Crea un iterador a partir de una serie de elementos.Array.from()
.forEach(f)Realiza acciones sobre los elementos..forEach()
.every(f)Comprueba si todos los elementos cumplen una condición..every()
.some(f)Comprueba si alguno de los elementos cumplen una condición..some()
.filter(f)Filtra los elementos que cumplen una condición..filter()
.map(f)Transforma los elementos a otro elemento derivado..map()
.flatMap(f)Transforma y aplana la estructura del elemento..flatMap()
.find(f)Busca un elemento que cumpla una condición..find()
.reduce(reducer, initial)Aplica una función a los elementos, acumulándolo a un elemento..reduce()

Tanto métodos como .forEach(), .map(), .filter(), .flatMap() y otros, como un equivalente al Array.from() que nos permite crear iteradores para estructuras de datos concretas.

Veamos nuevamente en un ejemplo:

  • 1️⃣ Creamos un array messages con con frases.
  • 2️⃣ Con Iterator.from() creamos un iterador que recorrerá dicha estructura (cada frase).
  • 3️⃣ El método .flatMap() permite hacer un .map() que aplana los elementos de un .
  • 4️⃣ Una función .map(text => text.split(" ")) separaría los en por espacios
  • 5️⃣ Pero como usamos .flatMap(), además aplanamos los
  • 6️⃣ Finalmente, con .values() nos quedamos con el iterador
  • 7️⃣ Reestructuramos con [...data] y obtenemos un con cada palabra
const messages = ["Hola a todos", "Estoy muy contento", "Adiós"];
const it = Iterator.from(messages);
const data = it.flatMap(text => text.split(" ").values());

[...data]   // ['Hola', 'a', 'todos', 'Estoy', 'muy', 'contento', 'Adiós']

Como habrás visto, una colección de utilidades muy interesantes y potentes para manipular y trabajar con datos mediante iteradores.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev