This page offers a great way to follow the default implementations and links to all the scaladoc.
The standard linked list.
scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)
You can cons them up as you would expect in a functional language.
scala> 1 :: 2 :: 3 :: Nil
res1: List[Int] = List(1, 2, 3)
Sets have no duplicates
scala> Set(1, 1, 2)
res2: scala.collection.immutable.Set[Int] = Set(1, 2)
Sequences have a defined order.
scala> Seq(1, 1, 2)
res3: Seq[Int] = List(1, 1, 2)
Maps are key value containers.
scala> Map('a' -> 1, 'b' -> 2)
res4: scala.collection.immutable.Map[Char,Int] = Map((a,1), (b,2))
These are all traits, both the mutable and immutable packages have implementations of these as well as specialized implementations.
All collections can be traversed. This trait you the standard function combinators written in terms of a foreach that you implement foreach.
Has an iterator() method to give you an Iterator over the elements.
Sequence of items with ordering.
A collection of items with no duplicates.
Key Value Pairs.
All of these methods below are available all the way down. The argument and return types types won’t always look the same as subclasses are free to override them.
def head : A
def tail : Traversable[A]
Here are where the Fuctional Combinators are defined.
def map [B] (f: (A) => B) : CC[B]
returns a collection with every element transformed by f
def foreach[U](f: Elem => U): Unit
mutates a collection by executing f over each element.
def find (p: (A) => Boolean) : Option[A]
returns the first element that matches the predicate funciton
def filter (p: (A) => Boolean) : Traversable[A]
returns a collection with all elements matching the predicate function
Partitioning:
def partition (p: (A) ⇒ Boolean) : (Traversable[A], Traversable[A])
Splits a collection into two halves based on a predicate function
def groupBy [K] (f: (A) => K) : Map[K, Traversable[A]]
Conversion:
Interestingly, you can convert one collection type to another.
def toArray : Array[A]
def toArray [B >: A] (implicit arg0: ClassManifest[B]) : Array[B]
def toBuffer [B >: A] : Buffer[B]
def toIndexedSeq [B >: A] : IndexedSeq[B]
def toIterable : Iterable[A]
def toIterator : Iterator[A]
def toList : List[A]
def toMap [T, U] (implicit ev: <:<[A, (T, U)]) : Map[T, U]
def toSeq : Seq[A]
def toSet [B >: A] : Set[B]
def toStream : Stream[A]
def toString () : String
def toTraversable : Traversable[A]
Let’s convert a Map to an Array. What you get is an Array of the Key Value pairs.
scala> Map(1 -> 2).toArray
res41: Array[(Int, Int)] = Array((1,2))
Adds access to an iterator.
def iterator: Iterator[A]
What does an Iterator give you?
def hasNext(): Boolean
def next(): A
This is very Java-esque. You often won’t see iterators used in Scala, you are much more likely to see the functional combinators or a for-comprehension used.
def contains(key: A): Boolean
def +(elem: A): Set[A]
def -(elem: A): Set[A]
Sequence of key and value pairs with lookup by key.
Pass a List of Pairs into apply() like so
scala> Map("a" -> 1, "b" -> 2)
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,2))
Or also like:
scala> Map(("a", 2), ("b", 2))
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,2), (b,2))
What is ->? That isn’t special syntax, it’s a method that returns a Tuple.
scala> "a" -> 2
res0: (java.lang.String, Int) = (a,2)
Remember, that is just sugar for
scala> "a".->(2)
res1: (java.lang.String, Int) = (a,2)
You can also build one up via ++
scala> Map.empty ++ List(("a", 1), ("b", 2), ("c", 3))
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,2), (c,3))
Quick lookup, the most commonly used forms of these collections.
A subclass of SortedMap, it gives you ordered access.
Fast random selection and fast updates.
scala> IndexedSeq(1, 2, 3)
res0: IndexedSeq[Int] = Vector(1, 2, 3)
Ordered sequence of Ints that are spaced apart. You will often see this used where a counting for-loop was used before.
scala> for (i <- 1 to 10) { println(i) }
1
2
3
4
5
6
7
8
9
10
Ranges have the standard functional combinators available to them.
scala> (1 to 10).map { i => i }
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Using apply methods on the traits will give you an instance of the default implementation, For instance, Iterable(1, 2) returns a List as it’s default implementation.
scala> Iterable(1, 2)
res0: Iterable[Int] = List(1, 2)
Same with Seq
scala> Seq(1, 2) res3: Seq[Int] = List(1, 2) scala> Iterable(1, 2) res1: Iterable[Int] = List(1, 2) scala> Sequence(1, 2) warning: there were deprecation warnings; re-run with -deprecation for details res2: Seq[Int] = List(1, 2)
Set
scala> Set(1, 2) res31: scala.collection.immutable.Set[Int] = Set(1, 2)
fast random-access of elements and a fast length operation.
fast access only to the first element via head, but also has a fast tail operation.
immutable
Pros
Con
Scala allows us to be pragmatic, it encourages immutability but does not penalize us for needing mutatability. This is very similar to var vs. val. We always start with val and move back to var when required.
We favor starting with the immutable versions of collections but switching to the mutable ones if performance dictates. Using immutable collections means you won’t accidentally change things in multiple threads.
All of the above classes we’ve discussed were immutable. Let’s discuss the commonly used mutable collections.
getOrElseUpdate
+=
scala> val numbers = collection.mutable.Map(1 -> 2) numbers: scala.collection.mutable.Map[Int,Int] = Map((1,2)) scala> numbers.get(1) res0: Option[Int] = Some(2) scala> numbers.getOrElseUpdate(2, 3) res54: Int = 3 scala> numbers res55: scala.collection.mutable.Map[Int,Int] = Map((2,3), (1,2)) scala> numbers += (4 -> 1) res56: numbers.type = Map((2,3), (4,1), (1,2))
+=
Interestingly, StringBuilder is a collection.
You can easily move between Java and Scala collection types using a set of implicit conversions that are available in the JavaConversions package.
import scala.collection.JavaConversions._ val sl = new scala.collection.mutable.ListBuffer[Int] val jl : java.util.List[Int] = sl val sl2 : scala.collection.mutable.Buffer[Int] = jl assert(sl eq sl2)
Two way conversions:
scala.collection.Iterable <=> java.lang.Iterable
scala.collection.Iterable <=> java.util.Collection
scala.collection.Iterator <=> java.util.{ Iterator, Enumeration }
scala.collection.mutable.Buffer <=> java.util.List
scala.collection.mutable.Set <=> java.util.Set
scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }
scala.collection.mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap
In addition, the following one way conversions are provided:
scala.collection.Seq => java.util.List
scala.collection.mutable.Seq => java.util.List
scala.collection.Set => java.util.Set
scala.collection.Map => java.util.Map