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
Related Data Structures
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.
Links
- Source: First.scala and Last.scala
- Tests: FirstLaws.scala and LastLaws.scala
- Scaladoc: First and Last
Documentation Help
We’d love your help fleshing out this documentation! You can edit this page in your browser by clicking this link.