Methods on the Scala collections classes, organized by category

(Note: I’m currently in the process of editing this page, so there may be a few errors in the examples and formatting while I do this.)

When I wrote the Scala Cookbook, I gave each recipe my full attention. I thought that if I wrote each recipe as well as possible, and included important recipes in each chapter, well, I wanted each chapter to be worth the price of the entire book. That was my goal.

As a result of this effort — and perhaps to the chagrin of my editor — the Scala collections chapters ended up being 130 pages in length.

One of the things I tried to do in Chapters 10 and 11 is to make sense and help organize the presentation of the collections classes and methods. For instance, in one recipe on choosing a collection class, I included information like the following table, which is a subset of a larger table:

Choosing a Scala collection class

In another table I show examples of how to call each collection method. The next image shows the beginning of a table that demonstrates the methods that are available on all Traversable collection classes:

Examples of how to use the Scala collections methods

In those examples I use c to stand for collection, f to stand for a function, and p to stand for a predicate.

Back to top

Categories

In another effort to help make sense of the collections methods, I broke them up into different categories of use. The following lists (and examples) show how I broke up those categories.

We’ll get to those examples in just a moment, but to show those examples we’ll first need some sample data to work with:

Sample Data
-----------

val evens = List(2, 4, 6)
val odds = List(1, 3, 5)

val a = "foo bar baz"
val foo = "foo"
val bar = "bar"
val names = List("Al", "Christina", "Kim")
val firstTen = (1 to 10).toList
val fiveToFifteen = (5 to 15).toList

Given that data, we can now look at the method categories along with examples of each method.

Back to top

1) Filtering methods

I think of filtering methods as being those methods that filter the original collection into a subset of the original collection, without changing any of the data during the filtering process. So, a filtering method will create a subset of the original collection, without changing any of the elements with an algorithm (such as multiplying each element by two, for example). Given that definition, here is a list of filtering methods available to Scala sequential collection classes:

  • distinct
  • drop
  • dropRight
  • dropWhile
  • filter
  • filterNot
  • find
  • head
  • headOption
  • init
  • last
  • lastOption
  • slice
  • tail
  • take
  • takeRight
  • takeWhile
  • toSet
  • withFilter

Here are examples of each of these methods:

a.distinct                # "fo barz"
a.drop(4)                 # "bar baz"
a.dropRight(2)            # "foo bar b"
a.dropWhile(_ != ' ')     # " bar baz"

a.filter(_ != 'a')        # "foo br bz"
a.filterNot(_ != 'a')     # "aa"
a.filterNot(_ == 'a')     # "foo br bz"
firstTen.find(_ > 4)      # Some(5)

a.head                    # f
a.headOption              # Some(f)

"foo bar".init            # "foo ba"

List(1,2,3).last          # 3
List(1,2,3).lastOption    # Some(3)

a.slice(0,5)              # foo b
a.slice(2,9)              # o bar b

a.tail                    # oo bar baz
a.take(3)                 # foo
a.takeRight(3)            # baz
a.takeWhile(_ != 'r')     # foo ba
Seq(1,1,2,2,3,3).toSet    # Set(1, 2, 3)

firstTen.withFilter(_ > 5)              # scala.collection.generic.FilterMonadic[Int,List[Int]]
firstTen.withFilter(_ > 5).map(_ * 1)   # List[Int] = List(6, 7, 8, 9, 10) 
Back to top

2) Transformer and reduction methods

Transformer methods take at least one input collection and apply a custom algorithm to that input collection to create a new output collection. Some of these methods can also reduce the original sequential collection down to one (or a few) derived values. These methods include:

  • +
  • ++
  • −−
  • collect
  • diff
  • distinct
  • flatMap
  • map
  • reverse
  • sortWith
  • takeWhile
  • zip
  • zipWithIndex

Here are examples of these collections methods:

evens ++ odds          # List(2, 4, 6, 1, 3, 5)
evens ++: odds         # List(2, 4, 6, 1, 3, 5)
0 +: evens             # List(0, 2, 4, 6)
odds :+ 7              # List(1, 3, 5, 7)
0 :: evens             # List(0, 2, 4, 6)
evens :: odds          # List(List(2, 4, 6), 1, 3, 5)
evens ::: odds         # List(2, 4, 6, 1, 3, 5)
(0 /: evens)(_ + _)    # 12
(evens :\ 0)(_ + _)    # 12

# collect and collectFirst take a partial function
firstTen.collect{case x if x % 2 == 0 => x}   # List(2, 4, 6, 8, 10)
firstTen.collectFirst{case x if x > 1 => x}   # Some(2)

a.diff("foo")                      # " bar baz"
a.distinct                         # "fo barz"

names.flatten                      # List(A, l, C, h, r, i, s, t, i, n, a, K, i, m)
names.flatMap(_.toUpperCase)       # List(A, L, C, H, R, I, S, T, I, N, A, K, I, M)

firstTen.groupBy(_ > 5)            # 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))

firstTen.indices                   # Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
"foo".indices                      # Range(0, 1, 2)

firstTen.intersect(fiveToFifteen)                  # List(5, 6, 7, 8, 9, 10)

a.map(_.toUpper)                   # FOO BAR BAZ
a.map(_.byteValue)                 # Vector(102, 111, 111, 32, 98, 97, 114, 32, 98, 97, 122)
a.mkString(",")                    # f,o,o, ,b,a,r, ,b,a,z
a.mkString("->", ",", "<-")        # ->f,o,o, ,b,a,r, ,b,a,z<-

a.par                              # a parallel array, ParArray(f, o, o,  , b, a, r,  , b, a, z)
a.partition(_ > 'e')               # (foorz, " ba ba")  # a Tuple2
firstTen.partition(_ > 5)          # (List(6, 7, 8, 9, 10),List(1, 2, 3, 4, 5))

a.replace('o', 'x')                # fxx bar baz
a.replace("o", "x")                # fxx bar baz
a.replaceAll("o", "x")             # fxx bar baz
a.replaceFirst("o", "x")           # fxo bar baz
firstTen.reverse                   # List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

# (more on scan, scanLeft, and scanRight below)
Seq(1,2,3,4,5).scan(1)(_ + _)         # List(1, 2, 4, 7, 11, 16)
Seq(1,2,3,4,5).scanLeft(1)(_ + _)     # List(1, 2, 4, 7, 11, 16)
Seq(1,2,3,4,5).scanRight(1)(_ + _)    # List(16, 15, 13, 10, 6, 1)

a.slice(0,5)                       # foo b
a.slice(2,9)                       # o bar b

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(4).toList         # List(List(1, 2, 3, 4), List(2, 3, 4, 5), List(3, 4, 5, 6), List(4, 5, 6, 7), List(5, 6, 7, 8), List(6, 7, 8, 9), List(7, 8, 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))

a.sortBy                           # this is a bit long; see below
a.sortWith(_ < _)                  # "  aabbfoorz"
a.sortWith(_ > _)                  # "zroofbbaa  "
a.sorted                           # "  aabbfoorz"

firstTen.span(_ < 5)               # (List(1, 2, 3, 4),List(5, 6, 7, 8, 9, 10))
a.split(" ")                       # Array(foo, bar, baz)
a.splitAt(3)                       # (foo," bar baz")
firstTen.startsWith(Seq(1,2))      # true

a.take(3)                          # foo
a.takeRight(3)                     # baz
a.takeWhile(_ != 'r')              # foo ba
a.toArray                          # Array(f, o, o,  , b, a, r,  , b, a, z)
a.toBuffer                         # ArrayBuffer(f, o, o,  , b, a, r,  , b, a, z)
a.toList                           # List(f, o, o,  , b, a, r,  , b, a, z)
Seq(1,1,2,2,3,3).toSet             # Set(1, 2, 3)
firstTen.toStream                  # scala.collection.immutable.Stream[Int] = Stream(1, ?)
a.toLowerCase                      # foo bar baz
a.toUpperCase                      # FOO BAR BAZ
a.toVector                         # Vector(f, o, o,  , b, a, r,  , b, a, z)
a.trim                             # "foo bar baz"

evens.union(odds)                  # List(2, 4, 6, 1, 3, 5)
unzip                              # see below
Seq(1,2,3).updated(0,10)           # List(10, 2, 3)

firstTen.view                      # scala.collection.SeqView[Int,List[Int]] = SeqView(...)

a.zip(0 to 10)                                # Vector((f,10), (o,11), (o,12), ( ,13), (b,14), (a,15), (r,16), ( ,17), (b,18), (a,19), (z,20))
Seq(1,2,3).zipAll(Seq('a', 'b'), 0, 'z')      # List((1,a), (2,b), (3,z))
Seq(1,2).zipAll(Seq('a', 'b', 'c'), 0, 'z')   # List((1,a), (2,b), (0,c))
a.zipWithIndex                                # Vector((f,0), (o,1), (o,2), ( ,3), (b,4), (a,5), (r,6), ( ,7), (b,8), (a,9), (z,10))



Back to top

3) Sorting methods

As the name implies, sorting methods let you create a new sequence from your initial sequence, where the new sequence has been sorted:

a.sortBy             # this is a bit long; see below
a.sortWith(_ < _)    # "  aabbfoorz"
a.sortWith(_ > _)    # "zroofbbaa  "
a.sorted             # "  aabbfoorz"

sortBy examples

To demonstrate the sortBy method we’ll need some more complicated sample data:

case class Person(firstName: String, lastName: String)

val fred = Person("Fred", "Flintstone")
val wilma = Person("Wilma", "Flintstone")
val barney = Person("Barney", "Rubble")
val betty = Person("Betty", "Rubble")

val people = List(betty, wilma, barney, fred)

Given that data, here’s a sortBy example:

people.sortBy(n => (n.lastName, n.firstName))

Here’s what a couple of examples look like in the Scala REPL:

scala> people.sortBy(n => (n.lastName, n.firstName))
res1: List[Person] = List(Person(Fred,Flintstone), Person(Wilma,Flintstone), Person(Barney,Rubble), Person(Betty,Rubble))

scala> people.sortBy(n => (n.firstName, n.lastName))
res2: List[Person] = List(Person(Barney,Rubble), Person(Betty,Rubble), Person(Fred,Flintstone), Person(Wilma,Flintstone))
Back to top

4) Grouping methods

These methods let you take an existing collection and create multiple groups from that one input collection. These methods include:

  • groupBy
  • grouped
  • partition
  • sliding
  • span
  • splitAt
  • unzip

Here are examples of these collection methods:

firstTen.groupBy(_ > 5)         # 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))

a.partition(_ > 'e')            # (foorz, " ba ba")  # 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(4).toList      # List(List(1, 2, 3, 4), List(2, 3, 4, 5), List(3, 4, 5, 6), List(4, 5, 6, 7), List(5, 6, 7, 8), List(6, 7, 8, 9), List(7, 8, 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))

firstTen.span(_ < 5)            # (List(1, 2, 3, 4),List(5, 6, 7, 8, 9, 10))
a.split(" ")                    # Array(foo, bar, baz)
a.splitAt(3)                    # (foo," bar baz")

unzip                           # see below

 

Back to top

5) Informational and mathematical methods

These methods provide information about a collection:

  • canEqual
  • contains
  • containsSlice
  • count
  • endsWith
  • exists
  • find
  • forAll
  • hasDefiniteSize
  • indexOf
  • indexOfSlice
  • indexWhere
  • isDefinedAt
  • isEmpty
  • lastIndexOf
  • lastIndexOfSlice
  • lastIndexWhere
  • max
  • min
  • nonEmpty
  • product
  • segmentLength
  • size
  • startsWith
  • sum

These methods can also be used with a function you supply to obtain information about a collection:

  • foldLeft
  • foldRight
  • reduceLeft
  • reduceRight

Here are examples of these Scala collection informational methods:

a.count(_ == 'a')                  # 2
a.endsWith("baz")                  # true
evens.exists(_ > 2)                # true

firstTen.find(_ > 4)               # Some(5)
firstTen.fold(0)(_ + _)            # 55
firstTen.foldLeft(0)(_ - _)        # 55
firstTen.foldRight(0)(_ - _)       # -5
evens.forall(_ >= 2)               # true

firstTen.hasDefiniteSize           # true
firstTen.toStream.hasDefiniteSize  # false (changes to 'true' after you consume the stream)

a.indexOf('a')                     # 5
firstTen.indexOf(5)                # 4
firstTen.indexOfSlice(Seq(4,5,6))  # 3
firstTen.indexWhere(_ == 5)        # 4
firstTen.indices                   # Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
"foo".indices                      # Range(0, 1, 2)

"foo".isDefinedAt(1)               # true
"foo".isDefinedAt(3)               # false

List(1,2,3).isEmpty                # false
Nil.isEmpty                        # true
None.isEmpty                       # true
Some(1).isEmpty                    # false
a.isEmpty                          # false

a.lastIndexOf('o')                                 # 2
List(1,1,2,2,1,1,3,3).lastIndexOfSlice(Seq(1,1))   # 4
List(1,1,2,2,1,1,3,3).lastIndexWhere(_ == 1)       # 5
a.length                                           # 11

names.max                          # "Kim"
names.min                          # "Al"

a.nonEmpty                         # true

firstTen.reduce(_ + _)             # 55
firstTen.reduceLeft(_ - _)         # -53
firstTen.reduceRight(_ - _)        # Int = -5

# segmentLength
List(1,2,3,4,5,4,3,2,1).segmentLength(_ > 3, 0)   # 0
List(1,2,3,4,5,4,3,2,1).segmentLength(_ > 3, 1)   # 0
List(1,2,3,4,5,4,3,2,1).segmentLength(_ > 3, 2)   # 0
List(1,2,3,4,5,4,3,2,1).segmentLength(_ > 3, 3)   # 3
List(1,2,3,4,5,4,3,2,1).segmentLength(_ > 3, 4)   # 2

a.size                             # 11

firstTen.startsWith(Seq(1,2))      # true
Back to top

6) Others

A few other methods are more difficult to categorize, including:

  • flatten - converts a list of lists down to one list
  • foreach - like a for loop, letting you iterate over the elements in a collection
  • mkString - lets you build a String from a collection
  • par - creates a parallel collection from an existing collection
  • view - creates a lazy view on a collection (see Recipe 10.24)

Here are examples of some of these Scala sequential collection methods:

foo * 3                            # foofoofoo
a.diff("foo")                      # " bar baz"

names.flatten                      # List(A, l, C, h, r, i, s, t, i, n, a, K, i, m)
names.flatMap(_.toUpperCase)       # List(A, L, C, H, R, I, S, T, I, N, A, K, I, M)

a.foreach(println(_))              # prints one character per line
a.foreach(println)                 # prints one character per line
a.getBytes.foreach(println)        # prints the byte value of each character, one value per line

firstTen.intersect(fiveToFifteen)  # List(5, 6, 7, 8, 9, 10)

a.mkString(",")                    # f,o,o, ,b,a,r, ,b,a,z
a.mkString("->", ",", "<-")        # ->f,o,o, ,b,a,r, ,b,a,z<-

a.par                              # a parallel array, ParArray(f, o, o,  , b, a, r,  , b, a, z)

a.replace('o', 'x')                # fxx bar baz
a.replace("o", "x")                # fxx bar baz
a.replaceAll("o", "x")             # fxx bar baz
a.replaceFirst("o", "x")           # fxo bar baz
firstTen.reverse                   # List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

a.sortBy                           # this is a bit long; see below
a.sortWith(_ < _)                  # "  aabbfoorz"
a.sortWith(_ > _)                  # "zroofbbaa  "
a.sorted                           # "  aabbfoorz"

evens.union(odds)                  # List(2, 4, 6, 1, 3, 5)
Seq(1,2,3).updated(0,10)           # List(10, 2, 3)

firstTen.view                      # scala.collection.SeqView[Int,List[Int]] = SeqView(...)

firstTen.withFilter(_ > 5)                    # scala.collection.generic.FilterMonadic[Int,List[Int]]
firstTen.withFilter(_ > 5).map(_ * 1)         # List[Int] = List(6, 7, 8, 9, 10)

a.zip(0 to 10)                                # Vector((f,10), (o,11), (o,12), ( ,13), (b,14), (a,15), (r,16), ( ,17), (b,18), (a,19), (z,20))
Seq(1,2,3).zipAll(Seq('a', 'b'), 0, 'z')      # List((1,a), (2,b), (3,z))
Seq(1,2).zipAll(Seq('a', 'b', 'c'), 0, 'z')   # List((1,a), (2,b), (0,c))
a.zipWithIndex                                # Vector((f,0), (o,1), (o,2), ( ,3), (b,4), (a,5), (r,6), ( ,7), (b,8), (a,9), (z,10))

 

Back to top

Summary

After you work with the Scala collections classes and methods for a while, many of these methods will become second nature. But when you’re first starting with Scala -- or need a quick reference on collections classes and methods you don’t use that often -- I hope that Chapters 10 and 11 in the Scala Cookbook are worth the price of the entire book.

Back to top

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.