Traversable ops – partition, span y otras chicas del montón

¿Nunca te ha pasado que te encuentras con una colección y quieres quedarte con dos partes de la colección: la que cumple un cierto predicado y el resto? ¿Acabas recurriendo a un filter y un filterNot? Tranquilo, en la teletienda entrada de hoy, veremos algunos de los métodos más comunes para dividir colecciones.

takeWhile

Para una colección Traversable[A], tenemos la notación:

def takeWhile(p: A => Boolean): Traversable[A]

Este método recibe como argumento la condición que deben cumplir los N primeros elementos a recolectar de la colección actual. Don’t worry: se ve mejor con un ejemplo:

val numbers = List(2, 4, 5, 6, 7)
val firstEven = numbers.takeWhile(_ % 2 == 0)
//List(2, 4)

Como podéis ver, la lista que se obtiene es el resultado de obtener los primeros elementos de la colección mientras se cumpla la condición indicada.

dropWhile

Al igual que su hermano mayor, dropWhile recibe como argumento una función, solo que su comportamiento se basa en eliminar todos los elementos desde el principio, hasta que deje de darse la condición que pasamos como argumento.

Por ejemplo:

val names = List("Julio", "Jose", "Alberto", "Javier")
val survivors = names.dropWhile(_.startsWith("J"))
//List("Alberto","Javier")

Fijaros que aunque hay otros elementos en la lista que cumplen la condición, el método dropWhile solamente eliminará los N primeros elementos mientras que todos ellos cumplan la condición. En el momento en que esta aserción no puede ser comprobada, el método deja de eliminar elementos.

span

Pero como decíamos en la introducción, ¿qué ocurre si quiero aplicar una de estas funciones sin perder el resto de elementos? En ese caso tu amigo es span

Su notación es

def span(p: A => Boolean): (Traversable[A], Traversable[A])

Y su funcionamiento, para que os hagáis una idea, es como devolver para una colección t y un predicado (función) f, (t takeWhile f, t dropWhile f), pero (y cito textualmente de la documentación de Scala) “posiblemente más eficiente”.

Ejemplos, ejemplos everywhere…

case class Event(timeStamp: Long)

val events: Stream[Event] = ???

val systemCrashTimestamp: Long = ???

val (eventsBeforeCrash,eventsAfterCrash) = 
  events.span(_.timeStamp <= systemCrashTimeStamp)

En este ejemplo, modelamos posibles eventos acontecidos en un sistema. Mediante un Stream, accedemos a los eventos acontecidos en el sistem a monitorizar. Por otra parte, se nos notifica del instante de un error fatal en el sistema (systemCrashTimeStamp).

942

Para separar los eventos que acontecieron antes del pete de la muerte, de los que siguieron después; usamos span (et voilà!)

partition

Ahora bien, si os fijasteis bien en los ejemplos que poníamos más arriba con takeWhile y dropWhile se podía intuir una problemática que consiste en separar los elementos que cumplen una cierta condición, de los que no; y takeWhile solo se quedaba con los primeros que lo cumplían, pero no con el resto.

Una primera aproximación, que seguro que alguno habréis usado antes de conocer el último método de este post, es la siguiente:

val numbers = List(2, 3, 4, 5, 6, 7)

val isEven: Int => Boolean = _ % 2 == 0

val even = numbers.filter(isEven)

val odd = numbers.filterNot(isEven)

Not bad. Pero al igual que con el método span podemos pensar en partition que para una colección t y un predicado (función) f, se comporta como sigue (t filter f, t filterNot f); haciendo la implementación mucho más sencilla (“y posiblemente más eficiente”):

val numbers = List(2, 3, 4, 5, 6, 7)

val isEven: Int => Boolean = _ % 2 == 0

val (even, odd) = numbers.partition(isEven)

2395690

Hasta el próximo tip.
¡Yogur de limón!

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s