First and Last

First[T] and Last[T] are data structures that keep track of, respectively, the earliest and latest instances of T that you’ve seen. First[T] works for any type T:

import com.twitter.algebird.{ First, Last }
// import com.twitter.algebird.{First, Last}

First(3) + First(2) + First(1)
// res0: com.twitter.algebird.First[Int] = First(3)

First("a") + First("b") + First("c")
// res1: com.twitter.algebird.First[String] = First(a)

As does Last[T]:

Last(3) + Last(2) + Last(1)
// res2: com.twitter.algebird.Last[Int] = Last(1)

Last("a") + Last("b") + Last("c")
// res3: com.twitter.algebird.Last[String] = Last(c)

Algebraic Properties

First[T] and Last[T] are both non-commutative semigroups. For First[T], the + function keeps the left input, while Last[T]’s + implementation keeps the right input. For example, for First[T]:

val first1 = First(1) + First(3) == First(1)
// first1: Boolean = true

val first3 = First(3) + First(1) == First(3)
// first3: Boolean = true

assert(first1 && first3)

And for Last[T]:

val last3 = Last(1) + Last(3) == Last(3)
// last3: Boolean = true

val last1 = Last(3) + Last(1) == Last(1)
// last1: Boolean = true

assert(last3 && last1)

Usage Examples

Let’s use First[T] and Last[T] to keep track of the first and last username that a Twitter user has followed over the lifetime of their account. First let’s define a type alias for Username:

type Username = String
// defined type alias Username

To track First and Last simultaneously we’ll use a combinator. As discussed on the Product Algebra docs page, the Tuple2[A, B] semigroup works by separately combining its left and right elements. This means that we can use a pair - a (First[Username], Last[Username]) - to track both the oldest and most recent twitter username that we’ve seen.

def follow(user: Username): (First[Username], Last[Username]) =
  (First(user), Last(user))
// follow: (user: Username)(com.twitter.algebird.First[Username], com.twitter.algebird.Last[Username])

Now let’s “add” up a few of these pairs, using the semigroup. First, we’ll import Algebird’s Operators._, which will enrich any semigroup with a + method.

import com.twitter.algebird.Operators._
// import com.twitter.algebird.Operators._

val follows = follow("sam") + follow("erik") + follow("oscar") + follow("kelley")
// follows: (com.twitter.algebird.First[Username], com.twitter.algebird.Last[Username]) = (First(sam),Last(kelley))

(First("sam"), Last("kelley")) == follows
// res6: Boolean = true

First[T] and Last[T] are related to Min[T] and Max[T]. All four of these data structures wrap up instances of another type T to make them combine in a different way. First[T] and Last[T] force them to combine based on the order that they’re seen in a stream. Min[T] and Max[T] force their combination to depend on the ordering of the type T.

See the docs on Min and Max for more information.

Documentation Help

We’d love your help fleshing out this documentation! You can edit this page in your browser by clicking this link.