Scala fits pretty well with list manipulations. Indeed, it facilitates their usage by defining a lot of methods that enable a lot of behaviors, such as filtering elements or grouping them based on an aggregation value. There are tons of such methods, and actually, if we need something to do something with a sequence, it should already be defined at http://www.scala-lang.org/api/current/index.html#scala.collection.Seq.
In the coming sections, we'll cover the most useful sequences when building Scala templates. First of all, let me just point to the fact that in Scala, when we think List
we mean Seq
.
The foreach
method provides a way to iterate over a sequence and apply a given function to each item. In object-oriented programming, we can think of it as a visitor pattern on a flat list.
The result of foreach
is Unit
, which is the Scala version of void
in Java.
The following screenshot shows how to use it:
As we can see, the Java code is less elegant and requires "boilerplate" (a Function0
implementation), but it explains well what the Scala code does.
The map
method is pretty much like the foreach
method, but instead of returning Unit
, map
returns a new sequence composed of the results of the function applied to each element. So it provides a way to adapt each element, while keeping them arranged in a sequence.
The following screenshot shows how to use it:
Here again, the Java version is more verbose, but reading the code would help you to understand the Scala version better than if it was explained in words
The name of this function is self-descriptive; it allows us to iterate over a sequence by applying a given predicate on each item, and returns a sequence of all the valid elements.
Let's jump into the code directly:
So short and so helpful, isn't it?
The code is pretty straightforward and self-descriptive. We ask the seq
sequence to be filtered using a predicate function that tests if the integer is even. So the result will be a new sequence of all the even elements in seq
.
This
exists
method is like contains
in Java, but it uses a comparison function rather than using equals.
The following screenshot shows how to make use of it:
It's that simple!
One of the common tasks with sequences is to retrieve an item that must match a predicate. Scala has the find
method for that, and it has a specific behavior when none of the elements match.
This method will iterate over the sequence by checking the predicate and return an Option[El]
value in all cases. An Option
is a special type in Scala that is meant to represent a value or non-value; it is explained as follows:
object None extends Option[Nothing]
: This extension of Option
simply represents a non-value. It'll be returned if no element has been found.case class Some[El](v:El) extends Option[El]
: This extension of Option
represents a wrapper over a value (v
).This type enforces the definition of a variable to be potentially undefined. We can also think of None
as a type-safe null
in Java, and it can be used as an alternative to exceptions. Indeed, if we have a function that parses String
as Int
, it could return an Option
of type Int
rather than an Int
type, so the user will be able to react to bad strings rather than catching the exception.
It's time to see it in action:
As the Option
structure is not available in Java, we had to define it (in some way) in order to mimic as much as possible of the Scala code.
The last method we'll see in this section is the apply
method. The Scala compiler has a special behavior for the
apply
method because it's not mandatory to call it explicitly.
Indeed, when a type declares an apply
method, we'll be able to call its instances as if they were functions. See the following screenshot for an example of this:
What is shown in the previous screenshot is an example of how we can create a template that has been rendered by giving a file and a list of arguments. It has a render
method that renders the file using the given parameters, which is called within the apply
method. As the goal of Renderer
is to create a usable representation of a template, it seems obvious that we should be able to call this task easily and in a readable manner. This is what is achieved in the two last statements.
Going back to the sequences, we can now imagine what the apply
method of a sequence would be, given that it takes an Int
type—it's the index of the requested element.
Sequences (iterables) define plenty of methods that are very useful and, truly, cover every use case that we'll encounter while dealing with them.
Following are some other functions that you might want to have a look at some time:
partition
: Based on a predicate, this function splits the sequence in twocollect
: This function mixes map
and filter
at oncegroupBy
: It takes a function that must produce the key values of a resulting map that packages all elements having the same key valuesliding
: This packages the elements using a window and slides it over the whole sequence (it is graceful in dealing with items that need to be shown in a predefined number of columns, for example, a gallery)length
: This returns the number of items in the sequence