Traversable ops – partition, span, among many other things

Has ever happened to you that you have a collection and you want to split it into two parts: one that satisfies certain assertion and the other one that doesn’t? In that case, do you resort to use a filter and a filterNot? Don’t worry, in this teleshopping ad post, we’ll see some not-so-popular but common methods for splitting collections.

takeWhile

For a Traversable[A] collection, we have the following method:

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

It gets as parameter the condition that has to be checked by the first N elements to be collected from current collection. Don’t worry, an example illustrates it better:

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

As you can see, the list you get is the result of getting the first elements in the collection while the given assertion is checked.

dropWhile

Like his elder brother, dropWhile receives as parameter a function, but its behavior is based on removing all elements from the beginning until the given condition is not checked.

E.g.:

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

Even though there are some other elements in the list that check the condition, method dropWhile only drop the first N elements as long as they all check the condition. At the very first moment the assertion is not validated, the method stop removing elements.

span

But as we were talking at the introduction, what happens if I want to apply one of this functions without loosing the remaining elements in the collection? In that case, span is your friend.

Its signature is:

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

And the way it works, just to picture it, is returning, for a t collection and a constraint(function) f, (t takeWhile f, t dropWhile f), but quoting Scala api) “possibly[sic] more efficient than”.

Examples, examples everywhere…

case class Event(timeStamp: Long)

val events: Stream[Event] = ???

val systemCrashTimestamp: Long = ???

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

In this example, we’re modeling possible events that may happen to a system. By reading some Stream, we access all events that occurred to the system to monitorize. On the other hand, we’re notified that some fatal-terrible error take place in the system (systemCrashTimeStamp).

942

For splitting events that took place before the death-fatal-error, from the other that happened later; we can use span (et voilà!)

partition

Ok then, if you looked closer before with takeWhile and dropWhile examples, a lil’ problem could be inferred: if you split collections this way, takeWhile only took first elements that checked the condition, but not all of them.

A first logical approach (that you may have used at some point), is to write something like this:

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. But like method span, we can think about partition like a method that, given a collection called t and a function f, behaves as follows: (t filter f, t filterNot f); making implementation much easier (and “possibly[sic] more efficient than”):

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

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

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

2395690

Until next tip.
Peace out!

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