The Scala List Class
List
is a linear, immutable sequence. All this means is that it’s a linked-list that you can’t modify. Any time you want to add or remove List
elements, you create a new List
from an existing List
.
Creating Lists
This is how you create an initial List
:
val ints = List(1, 2, 3)
val names = List("Joel", "Chris", "Ed")
You can also declare the List
’s type, if you prefer:
val ints: List[Int] = List(1, 2, 3)
val names: List[String] = List("Joel", "Chris", "Ed")
Adding elements to a List
Because List
is immutable you can’t add new elements to it. Instead you create a new list by prepending or appending elements to an existing List
. For instance, given this List
:
val a = List(1,2,3)
You prepend elements to a List
like this:
val b = 0 +: a
and this:
val b = List(-1, 0) ++: a
The REPL shows how this works:
scala> val b = 0 +: a
b: List[Int] = List(0, 1, 2, 3)
scala> val b = List(-1, 0) ++: a
b: List[Int] = List(-1, 0, 1, 2, 3)
You append elements to it while creating a new list like this:
val b = a :+ 4
and this:
val b = a ++ Vector(4, 5)
Again the REPL shows how this works:
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b = a :+ 4
b: List[Int] = List(1, 2, 3, 4)
scala> val b = a ++ Vector(4, 5)
b: List[Int] = List(1, 2, 3, 4, 5)
Because List
is a singly-linked list, you should really only prepend elements to it; appending elements to it is relatively slow, especially when you work with large sequences.
If you want to prepend and append elements to an immutable sequence, use
Seq
instead.
Here’s a summary of those examples:
val a = List(1,2,3)
// prepend
val b = 0 +: a
val b = List(-1, 0) ++: a
// append
val b = a :+ 4
val b = a ++ Vector(4, 5)
Because
List
is a linked-list class, you shouldn’t try to access the elements of large lists by their index value. For instance, if you have aList
with one million elements in it, accessing an element likemyList(999999)
will take a long time. If you want to access elements like this, use aSeq
orArrayBuffer
instead.
How to remember the method names
One way I remember those method names is to think that the :
character represents the side that the sequence is on, so when I use +:
I know that the list needs to be on the right, like this:
0 +: a
and when I use :+
I know the list needs to be on the left:
a :+ 4
There are more technical ways to think about this, but I find this to be a good way to remember the method names.
One good thing about these method names: They’re consistent. The same method names are used with other immutable sequence classes, such as Seq
and Vector
.
How to loop over lists
I showed how to loop over lists earlier in this book, but it’s worth showing the syntax again. Given a List
like this:
val names = List("Joel", "Chris", "Ed")
you can print each string like this:
for (name <- names) println(name)
This is what it looks like in the REPL:
scala> for (name <- names) println(name)
Joel
Chris
Ed
A great thing about this approach is that it works with all sequence classes, including ArrayBuffer
, List
, Seq
, Vector
, etc.
A little bit of history
If you’re interested in a little bit of history, the List
class is very similar to the List
class from the Lisp programming language. Indeed, in addition to the way I showed how to create a List
earlier, you can also create a List
like this:
val list = 1 :: 2 :: 3 :: Nil
The REPL shows how this works:
scala> val list = 1 :: 2 :: 3 :: Nil
list: List[Int] = List(1, 2, 3)
This works because a List
is a singly-linked list that ends with the Nil
element.
For much more information, see my book, Functional Programming, Simplified.
See also
For more information on how to work with List
s, see these resources: