(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:

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:

In those examples I use c to stand for collection, f to stand for a function, and p to stand for a predicate.
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.
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:
distinctdropdropRightdropWhilefilterfilterNotfindheadheadOptioninitlastlastOptionslicetailtaketakeRighttakeWhiletoSetwithFilter
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)
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:
+++−−−collectdiffdistinctflatMapmapreversesortWithtakeWhilezipzipWithIndex
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))
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))
4) Grouping methods
These methods let you take an existing collection and create multiple groups from that one input collection. These methods include:
groupBygroupedpartitionslidingspansplitAtunzip
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
5) Informational and mathematical methods
These methods provide information about a collection:
canEqualcontainscontainsSlicecountendsWithexistsfindforAllhasDefiniteSizeindexOfindexOfSliceindexWhereisDefinedAtisEmptylastIndexOflastIndexOfSlicelastIndexWheremaxminnonEmptyproductsegmentLengthsizestartsWithsum
These methods can also be used with a function you supply to obtain information about a collection:
foldLeftfoldRightreduceLeftreduceRight
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
6) Others
A few other methods are more difficult to categorize, including:
flatten- converts a list of lists down to one listforeach- like a for loop, letting you iterate over the elements in a collectionmkString- lets you build a String from a collectionpar- creates a parallel collection from an existing collectionview- 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))
| this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
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.