DEV Community

David Goyes
David Goyes

Posted on

Combine #7: Operadores de Secuencia

Encontrando valores

min() guarda en memoria todos los valores recibidos de un stream de entrada y, cuando recibe el evento de fin, emite el menor de esos valores, y luego termina. Para que esto pueda darse se requiere que los valores del stream de entrada conformen el protocolo Comparable, o usar el closure de predicado de min(by:).

let publisher = [1, -50, 246, 0].publisher
publisher
    .min()
    .sink( ... ) // -50
Enter fullscreen mode Exit fullscreen mode

max() guarda en memoria todos los valores recibidos de un stream de entrada y, cuando recibe el evento de fin, emite el mayor de esos valores, y luego termina. Para que esto pueda darse se requiere que los valores del stream de entrada conformen el protocolo Comparable, o usar el closure de predicado de max(by:).

let publisher = [1, -50, 246, 0].publisher
publisher
    .max()
    .sink( ... ) // 246
Enter fullscreen mode Exit fullscreen mode

first() publica el primer elemento de la secuencia y luego termina.

let publisher = ["A", "B", "C"].publisher
publisher
  .first()
  .sink( ... ) // A
Enter fullscreen mode Exit fullscreen mode

first(where:) publica el primer elemento de la secuencia que cumple con la condición del predicado y luego termina.

let publisher = ["A", "L", "Z"].publisher
publisher
  .first(where: { "HOLA".contains($0) })
  .sink( ... ) // L
Enter fullscreen mode Exit fullscreen mode

last() publica el último elemento de la secuencia y luego termina. Este operador espera hasta que el flujo de entrada emite un evento de fin; por esto, si no hay fin, no emite nada.

let publisher = ["A", "B", "C"].publisher
publisher
  .last()
  .sink( ... ) // C
Enter fullscreen mode Exit fullscreen mode

last(where:) publica el último elemento de la secuencia que cumple con la condición del predicado y luego termina.

let publisher = ["A", "L", "Z"].publisher
publisher
  .first(where: { "HOLA".contains($0) })
  .sink( ... ) // A
Enter fullscreen mode Exit fullscreen mode

output(at:) emite el i-ésimo elemento de una secuencia. Esta Subscription, cada vez que recibe un valor, demanda un valor más. De esta forma maneja el "backpressure".

let publisher = ["A", "L", "Z"].publisher
publisher
  .output(at: 1)
  .sink( ... ) // L
Enter fullscreen mode Exit fullscreen mode

output(in:) emite los elementos de una secuencia cuyos índices están dentro del rango pasado como argumento. Una vez que recibe todos los elementos dentro del rango especificado, se cancela la suscripción.

let publisher = ["A", "B", "C", "D", "E"].publisher
publisher
  .output(in: 1...3)
  .sink( ... ) // B, C, D
Enter fullscreen mode Exit fullscreen mode

Consultando información del Publisher

count() publica el número de eventos emitidos por un stream de entrada, como un único evento y luego termina.

let publisher = ["A", "B", "C", "D", "E"].publisher
publisher
  .count()
  .sink( ... ) // 5
Enter fullscreen mode Exit fullscreen mode

contains() emite true y cancela la suscripción (i.e. perezoso) si se encuentra, en la secuencia de entrada, el valor pasado por parámetro; o false en caso contrario. contains(where:) es la versión que recibe un closure predicado en lugar de un valor: si se cumple se emite true y se cancela la suscripción; o se emite false si no se cumple el predicado en toda la secuencia.

let publisher = ["A", "B", "C", "D", "E"].publisher
publisher
  .contains("C")
  .sink( ... ) // true
publisher
  .contains(where: { $0 == "F" || $0 == "E" })
  .sink( ... ) // true
Enter fullscreen mode Exit fullscreen mode

allSatisfy(_:) emite true si todos los elementos de la secuencia satisfacen la condición del predicado. Si al menos un elemento no satisface la condición, entonces se emite false y se cancela la suscripción.

let publisher = [0, 2, 4].publisher
publisher
  .allSatisfy { $0 % 2 == 0 }
  .sink( ... ) // true
Enter fullscreen mode Exit fullscreen mode

reduce(_:) recibe una semilla y un closure acumulador. El closure recibe el valor acumulado de la iteración anterior - empezando con la semilla - y el valor actual del stream de entrada. Este closure retorna un valor que servirá como valor acumulado de la siguiente iteración. Cuando el operador recibe el evento de fin, entonces emite el resultado y luego termina.

let publisher = [1, 2, 3].publisher
publisher
  .reduce(0) { $0 + $1 }
  .sink( ... ) // 6
Enter fullscreen mode Exit fullscreen mode

reduce se parece a scan en cuanto a que los dos acumulan valores. Sin embargo, scan emite el valor acumulado por cada valor recibido del stream de entrada, mientras que reduce emite un solo valor, cuando recibe el evento de fin del stream de entrada.


Cuestionario

1. ¿Qué diferencia hay entre first(where:) y last(where:) en cuanto al momento en que emiten valores?

2. ¿Por qué min() y max() necesitan que el tipo de datos conforme al protocolo Comparable?

3. ¿Qué sucede internamente con la suscripción cuando output(at:) emite su valor?

4. ¿Qué hace Combine cuando allSatisfy(_:) encuentra un valor que no cumple la condición?

5. Explica la diferencia entre reduce y scan en el contexto de Combine.

6. ¿Cuándo emite min() su valor? ✅

  • [ ] Cuando recibe el primer elemento
  • [ ] Cuando el Publisher termina
  • [ ] Cada vez que recibe un nuevo valor
  • [ ] Solo si hay un error

7. ¿Qué hace contains(where:) al encontrar un valor que cumple la condición? ✅

  • [ ] Emite true y continúa escuchando
  • [ ] Emite true y cancela la suscripción
  • [ ] Emite false y se detiene
  • [ ] Espera a que el Publisher termine

8. ¿Qué hace count() al finalizar el flujo? ✅

  • [ ] Emite la cantidad total de elementos recibidos
  • [ ] Emite el último valor recibido
  • [ ] Emite una lista con todos los valores
  • [ ] Reinicia el contador

9. ¿Qué operador emite solo el elemento en la posición indicada y cancela después? ✅

  • [ ] output(in:)
  • [ ] drop(while:)
  • [ ] output(at:)
  • [ ] first()

10. ¿Qué operador acumula valores y emite el resultado parcial en cada paso? ✅

  • [ ] reduce
  • [ ] scan
  • [ ] map
  • [ ] collect

Solución

1. ¿Qué diferencia hay entre first(where:) y last(where:) en cuanto al momento en que emiten valores?

first emite un valor tan pronto se cumple el predicado. last debe esperar a que termine la secuencia de entrada para emitir el último valor que cumple el predicado.

2. ¿Por qué min() y max() necesitan que el tipo de datos conforme al protocolo Comparable?

Para poder comparar los valores. En caso de que no sean Comparable, existe una versión sobrecargada del operador que recibe un closure de comparación.

3. ¿Qué sucede internamente con la suscripción cuando output(at:) emite su valor?

Se cancela.

4. ¿Qué hace Combine cuando allSatisfy(_:) encuentra un valor que no cumple la condición?

Emite un valor false y corta la suscripción.

5. Explica la diferencia entre reduce y scan en el contexto de Combine.

Ambos operadores acumulan valores de un stream de entrada. La diferencia radica en que reduce solo emite un valor al final, mientras que scan emite un valor acumulado cada vez que recibe un evento.

6. ¿Cuándo emite min() su valor? 

  • [✅] Cuando el Publisher termina

7. ¿Qué hace contains(where:) al encontrar un valor que cumple la condición?

  • [✅] Emite true y cancela la suscripción

8. ¿Qué hace count() al finalizar el flujo?

  • [✅] Emite la cantidad total de elementos recibidos

9. ¿Qué operador emite solo el elemento en la posición indicada y cancela después?

  • [✅] output(at:)

10. ¿Qué operador acumula valores y emite el resultado parcial en cada paso?

  • [✅] scan

Top comments (0)