Scala List class: 100+ method examples (map, filter, fold, reduce)

This page contains a large collection of examples of how to use the methods on the Scala List class.

Scala List class introduction

The List class is an immutable, linear, linked-list class. It’s very efficient when it makes sense for your algorithms to (a) prepend all new elements, (b) work with it in terms of its head and tail elements, and (c) use functional methods that traverse the list from beginning to end, such as filter, map, foldLeft, reduceLeft.

Because it’s a simple linked-list class, it’s not efficient for random access of elements. For example, accessing element people(987654321) of a List will require 987,654,320 operations. (But if it was a Vector, IndexedSeq, or ArrayBuffer, it would take only a few operations, because those sequences are stored as trees.)

Per the List class Scaladoc: “List has O(1) prepend and head/tail access. Most other operations are O(n) on the number of elements in the list. This includes the index-based lookup of elements, length, append and reverse.”

Tip: The List class is an immutable, linear sequence, and the Scala Vector class is an immutable, indexed sequence. Technically, Vector is the “go to” class when you want an immutable sequence, but developers often use List for small, immutable collections — especially when you’re okay with prepending items and you’ll be accessing elements from the head of the List (as opposed to random access of elements).

Notes about the following List examples

Remember that List is immutable, so in all of the examples that follow you need to assign the result of each expression to a new variable, like this:

val x = nums.distinct

As a second note, the following examples are demonstrated in a “CRUD+” order, meaning:

  • C — Create
  • R — Read
  • U — Update
  • D — Delete
  • + — demonstrates many methods available on the List class

CREATE: Create a new List with initial elements

There are two main ways to create and populate a List with initial elements:

# lisp style
val list = 1 :: 2 :: 3 :: Nil     # List[Int] = List(1, 2, 3)

# scala/java style
val nums = List(1, 2, 3)          # List[Int] = List(1, 2, 3)

When the values in the list have mixed/multiple types you may want to specify the type of the list:

val x = List(1, 1.0, 1F)                 # List[Double] = List(1.0, 1.0, 1.0)
val x: List[Number] = List(1, 1.0, 1F)   # List[Number] = List(1, 1.0, 1.0)

A custom example:

trait Animal
trait Furry
case class Dog(name: String) extends Animal with Furry
case class Cat(name: String) extends Animal with Furry

# (a) resulting type is `List[Product with Serializable with Animal with Furry]`
val animalHouse = List(
    Dog("Rover"),
    Cat("Felix")
)

# (b) be clear you want `List[Animal]`
val animalHouse: List[Animal] = List(
    Dog("Rover"),
    Cat("Felix")
)

If you ever need to create an empty list:

val nums = List[Int]()            # List[Int] = List()

Remember the construction syntax is just syntactic sugar for apply:

val nums = List(1, 2, 3)          # List(1, 2, 3)
val nums = List.apply(1, 2, 3)    # List(1, 2, 3)

CREATE: Create a new List by populating it

You can create a new List that’s populated with initial elements using a Range:

# to, until
(1 to 5).toList                   # List(1, 2, 3, 4, 5)
(1 until 5).toList                # List(1, 2, 3, 4)

(1 to 10 by 2).toList             # List(1, 3, 5, 7, 9)
(1 until 10 by 2).toList          # List(1, 3, 5, 7, 9)
(1 to 10).by(2).toList            # List(1, 3, 5, 7, 9)

('d' to 'h').toList               # List(d, e, f, g, h)
('d' until 'h').toList            # List(d, e, f, g)

('a' to 'f').by(2).toList         # List(a, c, e)

# range method
List.range(1, 3)                  # List(1, 2)
List.range(1, 6, 2)               # List(1, 3, 5)

You can also use the fill and tabulate methods:

List.fill(3)("foo")               # List(foo, foo, foo)
List.tabulate(3)(n => n * n)      # List(0, 1, 4)
List.tabulate(4)(n => n * n)      # List(0, 1, 4, 9)

READ: How to access Scala List elements

As with other Scala sequence classes, you access List elements by their index, inside parentheses:

val names = List("bert", "ernie", "oscar")
names(0)    # "bert"
names(1)    # "ernie"
names(2)    # "oscar"

You can also read/access List elements in for loops and for expressions, as shown here:

val oneToFive = List(1, 2, 3, 4, 5)
for (i <- oneToFive) yield i         # List(1, 2, 3, 4, 5)
for (i <- oneToFive) yield i * 2     # List(2, 4, 6, 8, 10)
for (i <- oneToFive) yield i % 2     # List(1, 0, 1, 0, 1)

UPDATE: How to add (append and prepend) elements to a List

The List class is a little bit of a special creature. As noted above from the Scaladoc:

List has O(1) prepend and head/tail access. Most other operations are O(n) on the number of elements in the list.”

The proper, recommended way to work with List

In general, the proper way to work with a List is to always prepend elements to a list with the ::, like this:

val a = List(2,3)   # List(2,3)
val b = 1 :: a      # List(1, 2, 3)
val c = 0 :: b      # List(0, 1, 2, 3)

In general, whenever you work with a List you should think of it in terms of these operations:

  • ::
  • head
  • tail

Other functional methods that walk the entire list from beginning to end, such as filter, map, foldLeft, and reduceLeft also make sense with List.

Other methods you can use on List (that may be slow)

Because List is immutable, you can’t add elements to an existing List. The way you work with List is to modify the elements it contains as you assign the results to a new List.

Method Description Example
:+ append 1 item oldList :+ e
++ append N items oldList ++ newList
+: prepend 1 item e +: oldList
++: prepend N items newList ++: oldList

Again, you can use these methods, but it’s not recommended.

Append and prepend examples

These examples show how to use the append and prepend methods:

val v1 = List(4,5,6)        # List(4, 5, 6)
val v2 = v1 :+ 7            # List(4, 5, 6, 7)
val v3 = v2 ++ List(8,9)    # List(4, 5, 6, 7, 8, 9)

val v4 = 3 +: v3            # List(3, 4, 5, 6, 7, 8, 9)
val v5 = List(1,2) ++: v4   # List(1, 2, 3, 4, 5, 6, 7, 8, 9)

About the : character in the method names

Note that during these operations the : character is always next to the old (original) sequence. I use that as a way to remember these methods.

The correct technical way to think about this is that a Scala method name that ends with the : character is right-associative, meaning that the method comes from the variable on the right side of the expression. Therefore, with +: and ++:, these methods comes from the List that’s on the right of the method name.

UPDATE: How to “update” List elements

Because List is immutable, you can’t update elements in place, but depending on your definition of “update,” there are a variety of methods that let you update a List as you assign the result to a new variable:

Method Returns
collect(pf) A new collection by applying the partial function pf to all elements of the list, returning elements for which the function is defined
distinct A new sequence with no duplicate elements
flatten Transforms a list of lists into a single list
flatMap(f) When working with sequences, it works like map followed by flatten
map(f) Return a new sequence by applying the function f to each element in the List
updated(i,v) A new list with the element at index i replaced with the new value v
union(s) A new list that contains elements from the current list and the sequence s
val x = List(Some(1), None, Some(3), None)

x.collect{case Some(i) => i}        # List(1, 3)

val x = List(1,2,1,2)
x.distinct                          # List(1, 2)
x.map(_ * 2)                        # List(2, 4, 2, 4)
x.updated(0,100)                    # List(100, 2, 1, 2)

val a = List(List(1,2), List(3,4))
a.flatten                           # List(1, 2, 3, 4)

val fruits = List("apple", "pear")
fruits.map(_.toUpperCase)           # List(APPLE, PEAR)
fruits.flatMap(_.toUpperCase)       # List(A, P, P, L, E, P, E, A, R)

List(2,4).union(List(1,3))          # List(2, 4, 1, 3)

DELETE: Filtering methods (how to “remove” elements from a List)

A List is an immutable sequence, so you don’t remove elements from it. Instead, you describe how to remove elements as you assign the results to a new collection. These methods let you “remove” elements during this process:

Method Description
distinct Return a new sequence with no duplicate elements
drop(n) Return all elements after the first n elements
dropRight(n) Return all elements except the last n elements
dropWhile(p) Drop the first sequence of elements that matches the predicate p
filter(p) Return all elements that match the predicate p
filterNot(p) Return all elements that do not match the predicate p
find(p) Return the first element that matches the predicate p
head Return the first element; can throw an exception if the List is empty
headOption Returns the first element as an Option
init All elements except the last one
intersect(s) Return the intersection of the list and another sequence s
last The last element; can throw an exception if the List is empty
lastOption The last element as an Option
slice(f,u) A sequence of elements from index f (from) to index u (until)
tail All elements after the first element
take(n) The first n elements
takeRight(n) The last n elements
takeWhile(p) The first subset of elements that matches the predicate p

Examples

val a = List(10, 20, 30, 40, 10)      # List(10, 20, 30, 40, 10)
a.distinct                            # List(10, 20, 30, 40)
a.drop(2)                             # List(30, 40, 10)
a.dropRight(2)                        # List(10, 20, 30)
a.dropWhile(_ < 25)                   # List(30, 40, 10)
a.filter(_ < 25)                      # List(10, 20, 10)
a.filter(_ > 100)                     # List()
a.filterNot(_ < 25)                   # List(30, 40)
a.find(_ > 20)                        # Some(30)
a.head                                # 10
a.headOption                          # Some(10)
a.init                                # List(10, 20, 30, 40)
a.intersect(List(19,20,21))           # List(20)
a.last                                # 10
a.lastOption                          # Some(10)
a.slice(2,4)                          # List(30, 40)
a.tail                                # List(20, 30, 40, 10)
a.take(3)                             # List(10, 20, 30)
a.takeRight(2)                        # List(40, 10)
a.takeWhile(_ < 30)                   # List(10, 20)

As noted, head and last can throw exceptions:

scala> val a = List[Int]()
a: List[Int] = List()

scala> a.head
java.util.NoSuchElementException: head of empty list
  at scala.collection.immutable.Nil$.head(List.scala:428)
  at scala.collection.immutable.Nil$.head(List.scala:425)
  ... 28 elided

scala> a.last
java.util.NoSuchElementException
  at scala.collection.LinearSeqOptimized.last(LinearSeqOptimized.scala:146)
  at scala.collection.LinearSeqOptimized.last$(LinearSeqOptimized.scala:145)
  at scala.collection.immutable.List.last(List.scala:86)
  ... 28 elided

MORE: Transformer methods

A transformer method is a method that constructs a new collection from an existing collection.

Method Returns
collect(pf) Creates a new collection by applying the partial function pf to all elements of the list, returning elements for which the function is defined
diff(c) The difference between this list and the collection c
distinct A new sequence with no duplicate elements
flatten Transforms a list of lists into a single list
flatMap(f) When working with sequences, it works like map followed by flatten
map(f) A new sequence by applying the function f to each element in the List
reverse A new sequence with the elements in reverse order
sortWith(f) A new sequence with the elements sorted with the use of the function f
updated(i,v) A new List with the element at index i replaced with the new value v
union(c) A new sequence that contains all elements of the list and the collection c
zip(c) A collection of pairs by matching the list with the elements of the collection c
zipWithIndex A list of each element contained in a tuple along with its index
val x = List(Some(1), None, Some(3), None)

x.collect{case Some(i) => i}          # List(1, 3)

# diff
val oneToFive = (1 to 5).toList       # List(1, 2, 3, 4, 5)
val threeToSeven = (3 to 7).toList    # List(3, 4, 5, 6, 7)
oneToFive.diff(threeToSeven)          # List(1, 2)
threeToSeven.diff(oneToFive)          # List(6, 7)

List(1,2,1,2).distinct                # List(1, 2)

val a = List(List(1,2), List(3,4))
a.flatten                             # List(1, 2, 3, 4)

# map, flatMap
val fruits = List("apple", "pear")
fruits.map(_.toUpperCase)             # List(APPLE, PEAR)
fruits.flatMap(_.toUpperCase)         # List(A, P, P, L, E, P, E, A, R)

List(1,2,3).reverse                   # List(3, 2, 1)

val nums = List(10, 5, 8, 1, 7)
nums.sorted                           # List(1, 5, 7, 8, 10)
nums.sortWith(_ < _)                  # List(1, 5, 7, 8, 10)
nums.sortWith(_ > _)                  # List(10, 8, 7, 5, 1)

List(1,2,3).updated(0,10)             # List(10, 2, 3)
List(2,4).union(List(1,3))            # List(2, 4, 1, 3)

# zip
val women = List("Wilma", "Betty")    # List(Wilma, Betty)
val men = List("Fred", "Barney")      # List(Fred, Barney)
val couples = women.zip(men)          # List((Wilma,Fred), (Betty,Barney))

val a = List.range('a', 'e')          # List(a, b, c, d)
a.zipWithIndex                        # List((a,0), (b,1), (c,2), (d,3))

MORE: Informational and mathematical methods

These methods let you obtain information from a collection.

Method Returns
contains(e) True if the list contains the element e
containsSlice(s) True if the list contains the sequence s
count(p) The number of elements in the list for which the predicate is true
endsWith(s) True if the list ends with the sequence s
exists(p) True if the predicate returns true for at least one element in the list
find(p) The first element that matches the predicate p, returned as an Option
forall(p) True if the predicate p is true for all elements in the list
hasDefiniteSize True if the list has a finite size
indexOf(e) The index of the first occurrence of the element e in the list
indexOf(e,i) The index of the first occurrence of the element e in the list, searching only from the value of the start index i
indexOfSlice(s) The index of the first occurrence of the sequence s in the list
indexOfSlice(s,i) The index of the first occurrence of the sequence s in the list, searching only from the value of the start index i
indexWhere(p) The index of the first element where the predicate p returns true
indexWhere(p,i) The index of the first element where the predicate p returns true, searching only from the value of the start index i
isDefinedAt(i) True if the list contains the index i
isEmpty True if the list contains no elements
lastIndexOf(e) The index of the last occurrence of the element e in the list
lastIndexOf(e,i) The index of the last occurrence of the element e in the list, occurring before or at the index i
lastIndexOfSlice(s) The index of the last occurrence of the sequence s in the list
lastIndexOfSlice(s,i) The index of the last occurrence of the sequence s in the list, occurring before or at the index i
lastIndexWhere(p) The index of the first element where the predicate p returns true
lastIndexWhere(p,i) The index of the first element where the predicate p returns true, occurring before or at the index i
max The largest element in the list
min The smallest element in the list
nonEmpty True if the list is not empty (i.e., if it contains 1 or more elements)
product The result of multiplying the elements in the collection
segmentLength(p,i) The length of the longest segment for which the predicate p is true, starting at the index i
size The number of elements in the list
startsWith(s) True if the list begins with the elements in the sequence s
startsWith(s,i) True if the list has the sequence s starting at the index i
sum The sum of the elements in the list
fold(s)(o) “Fold” the elements of the list using the binary operator o, using an initial seed s (see also reduce)
foldLeft(s)(o) “Fold” the elements of the list using the binary operator o, using an initial seed s, going from left to right (see also reduceLeft)
foldRight(s)(o) “Fold” the elements of the list using the binary operator o, using an initial seed s, going from right to left (see also reduceRight)
reduce “Reduce” the elements of the list using the binary operator o
reduceLeft “Reduce” the elements of the list using the binary operator o, going from left to right
reduceRight “Reduce” the elements of the list using the binary operator o, going from right to left

Examples

First, some sample data:

val evens = List(2, 4, 6)                  # List(2, 4, 6)
val odds = List(1, 3, 5)                   # List(1, 3, 5)
val fbb = "foo bar baz"                    # String = foo bar baz
val firstTen = (1 to 10).toList            # List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val fiveToFifteen = (5 to 15).toList       # List(5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
val empty = List[Int]()                    # List[Int] = List()
val letters = ('a' to 'f').toList          # List(a, b, c, d, e, f)

The examples:

evens.contains(2)                          # true
firstTen.containsSlice(List(3,4,5))        # true
firstTen.count(_ % 2 == 0)                 # 5
firstTen.endsWith(List(9,10))              # true
firstTen.exists(_ > 10)                    # false
firstTen.find(_ > 2)                       # Some(3)
firstTen.forall(_ < 20)                    # true
firstTen.hasDefiniteSize                   # true
empty.hasDefiniteSize                      # true
letters.indexOf('b')                       # 1 (zero-based)
letters.indexOf('d', 2)                    # 3
letters.indexOf('d', 3)                    # 3
letters.indexOf('d', 4)                    # -1
letters.indexOfSlice(List('c','d'))        # 2
letters.indexOfSlice(List('c','d'),2)      # 2
letters.indexOfSlice(List('c','d'),3)      # -1
firstTen.indexWhere(_ == 3)                # 2
firstTen.indexWhere(_ == 3, 2)             # 2
firstTen.indexWhere(_ == 3, 5)             # -1
letters.isDefinedAt(1)                     # true
letters.isDefinedAt(20)                    # false
letters.isEmpty                            # false
empty.isEmpty                              # true

# lastIndex...
val fbb = "foo bar baz"
fbb.indexOf('a')                           # 5
fbb.lastIndexOf('a')                       # 9
fbb.lastIndexOf('a', 10)                   # 9
fbb.lastIndexOf('a', 9)                    # 9
fbb.lastIndexOf('a', 6)                    # 5
fbb.lastIndexOf('a', 5)                    # 5
fbb.lastIndexOf('a', 4)                    # -1

fbb.lastIndexOfSlice("ar")                 # 5
fbb.lastIndexOfSlice(List('a','r'))        # 5
fbb.lastIndexOfSlice(List('a','r'), 4)     # -1
fbb.lastIndexOfSlice(List('a','r'), 5)     # 5
fbb.lastIndexOfSlice(List('a','r'), 6)     # 5

fbb.lastIndexWhere(_ == 'a')               # 9
fbb.lastIndexWhere(_ == 'a', 4)            # -1
fbb.lastIndexWhere(_ == 'a', 5)            # 5
fbb.lastIndexWhere(_ == 'a', 6)            # 5
fbb.lastIndexWhere(_ == 'a', 8)            # 5
fbb.lastIndexWhere(_ == 'a', 9)            # 9

firstTen.max                               # 10
letters.max                                # f
firstTen.min                               # 1
letters.min                                # a
letters.nonEmpty                           # true
empty.nonEmpty                             # false
firstTen.product                           # 3628800
letters.size                               # 6

val x = List(1,2,9,1,1,1,1,4)
x.segmentLength(_ < 4, 0)                  # 2
x.segmentLength(_ < 4, 2)                  # 0
x.segmentLength(_ < 4, 3)                  # 4
x.segmentLength(_ < 4, 4)                  # 3

firstTen.startsWith(List(1,2))             # true
firstTen.startsWith(List(1,2), 0)          # true
firstTen.startsWith(List(1,2), 1)          # false
firstTen.sum                               # 55

firstTen.fold(100)(_ + _)                  # 155
firstTen.foldLeft(100)(_ + _)              # 155
firstTen.foldRight(100)(_ + _)             # 155
firstTen.reduce(_ + _)                     # 55
firstTen.reduceLeft(_ + _)                 # 55
firstTen.reduceRight(_ + _)                # 55

firstTen.fold(100)(_ - _)                  # 45
firstTen.foldLeft(100)(_ - _)              # 45
firstTen.foldRight(100)(_ - _)             # 95
firstTen.reduce(_ - _)                     # -53
firstTen.reduceLeft(_ - _)                 # -53
firstTen.reduceRight(_ - _)                # -5

Note: Methods like foldRight and reduceRight are not recommended with List because they will be very slow for large collections.

More on fold and reduce

MORE: Grouping methods

These methods generally let you create multiple groups from a collection.

Method Returns
groupBy(f) A map of collections created by the function f
grouped Breaks the list into fixed-size iterable collections
partition(p) Two collections created by the predicate p
sliding(i,s) Group elements into fixed size blocks by passing a sliding window of size i and step s over them
span(p) A collection of two collections; the first created by list.takeWhile(p), and the second created by list.dropWhile(p)
splitAt(i) A collection of two collections by splitting the list at index i
unzip The opposite of zip, breaks a collection into two collections by dividing each element into two pieces; such as breaking up a list of Tuple2 elements

Examples

val firstTen = (1 to 10).toList       # List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

firstTen.groupBy(_ > 5)               # Map[Boolean,List[Int]] = Map(false -> List(1, 2, 3, 4, 5), true -> List(6, 7, 8, 9, 10))
firstTen.grouped(2)                   # Iterator[List[Int]] = non-empty iterator
firstTen.grouped(2).toList            # List(List(1, 2), List(3, 4), List(5, 6), List(7, 8), List(9, 10))
firstTen.grouped(5).toList            # List(List(1, 2, 3, 4, 5), List(6, 7, 8, 9, 10))

"foo bar baz".partition(_ < 'c')      # (" ba ba", foorz)  # a Tuple2
firstTen.partition(_ > 5)             # (List(6, 7, 8, 9, 10),List(1, 2, 3, 4, 5))

firstTen.sliding(2)                   # Iterator[List[Int]] = non-empty iterator
firstTen.sliding(2).toList            # List(List(1, 2), List(2, 3), List(3, 4), List(4, 5), List(5, 6), List(6, 7), List(7, 8), List(8, 9), List(9, 10))
firstTen.sliding(2,2).toList          # List(List(1, 2), List(3, 4), List(5, 6), List(7, 8), List(9, 10))
firstTen.sliding(2,3).toList          # List(List(1, 2), List(4, 5), List(7, 8), List(10))
firstTen.sliding(2,4).toList          # List(List(1, 2), List(5, 6), List(9, 10))

val x = List(15, 10, 5, 8, 20, 12)
x.groupBy(_ > 10)                     # Map(false -> List(10, 5, 8), true -> List(15, 20, 12))
x.partition(_ > 10)                   # (List(15, 20, 12),List(10, 5, 8))
x.span(_ < 20)                        # (List(15, 10, 5, 8),List(20, 12))
x.splitAt(2)                          # (List(15, 10),List(5, 8, 20, 12))

More information:

MORE: Looping over a List with for and foreach

These examples show how to loop/iterate over a vector with for and foreach. (As I write in Functional Programming, Simplified, foreach is only used for side effects, and therefore I rarely use it.)

val oneToFive = List(1, 2, 3, 4, 5)   # List[Int] = List(1, 2, 3, 4, 5)

for (i <- oneToFive) yield i          # List[Int] = List(1, 2, 3, 4, 5)
for (i <- oneToFive) yield i * 2      # List[Int] = List(2, 4, 6, 8, 10)
for (i <- oneToFive) yield i % 2      # List[Int] = List(1, 0, 1, 0, 1)

for {                                 # List[Int] = List(3, 4, 5)
    i <- oneToFive
    if i > 2
} yield i

for {                                 # List[Int] = List(6, 8, 10)
    i <- oneToFive
    if i > 2
} yield {
    # could be multiple lines here
    i * 2
}

# foreach (which i rarely use)
val oneToThree = List(1, 2, 3)
oneToThree.foreach(print)            # 123
for (i <- oneToThree) print(i)       # 123

A few things you can do with a List of Options

The Option type is used a lot in idiomatic Scala code, so here are some ways to work with a Vector that contains Options.

val x = List(Some(1), None, Some(3), None)   # List[Option[Int]] = List(Some(1), None, Some(3), None)

x.flatten                                    # List[Int] = List(1, 3)
x.collect{case Some(i) => i}                 # List[Int] = List(1, 3)


# map, flatten, flatMap
import scala.util.Try
def toInt(s: String): Option[Int] = Try(Integer.parseInt(s)).toOption
val strings = List("1", "2", "foo", "3", "bar")

strings.map(toInt)                   # List[Option[Int]] = List(Some(1), Some(2), None, Some(3), None)
strings.map(toInt).flatten           # List[Int] = List(1, 2, 3)
strings.flatMap(toInt)               # List[Int] = List(1, 2, 3)

Scala List summary

In summary, I hope these List examples are helpful.

All the best,
Al