Scala Collections – Streams, Maps & Sets


Stream is similar to a List however, it can have unlimited elements. It is a Traversable but lazy in nature. A Stream in Scala consists of a head and tail which is lazily computed i.e elements are only evaluated when they are needed. Hence it can be inferred, laziness helps to make streams infinite. Transformer functions like map, filter etc are also applied lazily although care should be taken that not all functions are lazy – i.e max, sum etc.

val s = Stream(1,2,3,4,5)

//prints the value 1

//prints Stream(1,?) - the tail is lazily evaluated

Elements can be added to a stream as below. Keep in mind that when you are adding an element to the stream we also need to append Stream.empty

Additionally also checkout the #::: that is only required after the stream name and then it is #::

val s = Stream(1,2,3,4,5)

//Append two elements to a stream
val newStream = s #::: 6 #:: 7 #:: Stream.Empty

//Prints - 1,2,3,4,5,6,7

//Append one element to a stream
val oneMoreStream = s #::: 6 #:: Stream.Empty
//Prints - 1,2,3,4,5,6

Transformer methods are lazily evaluated as show below – e.g filter

//Slightly different way to
//create a stream of elements from 1 to 20
val s = (1 to 20).toStream

//Apply transformer function - filter
val filteredStream = s.filter(_ % 2==0)

//prints - 2

//prints - Stream(4,?)

//prints - 2,4,6,8,10

Transformer methods are lazily evaluated as show below – e.g map

//Create a stream of elements from 1 to 20
val s = (1 to 5).toStream

//Apply transformer function - map. Multiply each element by 2
val newStream =* 2)

//prints - 2

//prints - Stream(4,?)

//prints - 2,4,6,8,10


Set in Scala is an Iterable which has contains no duplicates and all elements are unique in a set. Sets by default are immutable but if mutable sets are required then they can be imported from scala.collection.mutable.Set

If there are elements added to sets which are already available then those elements are not added to the set. No errors are given.

//Creates a set of 5 unique elements
val set = Set(1,2,3,4,5,5)

//Prints 1,2,3,4,5

Adding a set/element to a set results in a new set as by default they are immutable. See below. In case, we try to remove an element from the set and the element is not in the set no error is generated.

val set = Set(1,2,3,4,5)

//Adds a new element to set
val addSet = set + (6)

//Prints - 1,2,3,4,5,6

//Remove an element from a set
val remSet = set - (5)

Sets in scala are immutable by default. There are some operations – union, intersect & diff which are typically applied to sets but these are also available to other collections. There are mathematical operators also available instead of union, intersect and diff

  • Instead of union use ++
  • Instead of intersect use &
  • Instead of diff use &~
val set1 = Set(1,2,3,4,5)
val set2 = Set(4,5,6,7,8,9)

//Create a union of two sets
val unionSet = set1.union(set2)

//Prints all the elements - 1,2,3,4,5,6,7,8,9

//Create an intersection of two sets
val intersectSet = set1.intersect(set2)

//Prints all the elements - 4,5

//Create a diff for set1 - all elements in set1 not in set2
val diffSet1 = set1.diff(set2)

//Prints all the elements - 1,2,3

//Create a diff for set2 - all elements in set1 not in set1
val diffSet2 = set2.diff(set1)

//Prints all the elements - 6,7,8,9


Finally, let’s talk about scala Maps. Like lists, maps are also one of more widely used data structures. If you work on key-value pairs you would love maps. Maps also find use in lookups and there is a rich set of operators available. Do not confuse this with the transformer method map. By default Scala maps are immutable but you can create mutable maps by using

Maps can be defined a simple key->Value or as a tuple (Key,Value). See below

val map1 = Map(1 -> "One", 2 -> "Two", 3 -> "Three")
val map2 = Map((1,"One"),(2,"Two"),(3,"Three"))

In both the cases map created is the same. Only difference is the syntax.

Maps can be iterated or looped thru in a few ways. Tuple form tend to be shorter but the longer form tend to make the code a bit more clear(really a personal choice). See below

val map1 = Map(1 -> "One", 2 -> "Two", 3 -> "Three")

//Prints the output - "Key is 1 and Value is One"
for((k,v) println("Key is " + x._1 + " and Value is " + x._2))

//Using case
map1.foreach(case(k,v)=>println("Key is " + k + " and Value is " + v)

Before we dive into looks let’s see how we can extract the keys or values of a map separately. There are many ways to do it. See below

val map1 = Map((1,"One"),(2,"Two"),(3,"Three"))
//Returns a Set collection object i.e Unique elements
val k = map1.keys
//Returns a list of all unique values
val v = map1.values.toList

Lookups can also be implemented in many ways. If the map does not find a key it throws an exception – java.util.NoSuchElementException. There are a couple of ways to handle this either by defining a default value when such a situation occurs or use getOrElse. See below

//Happy Path. Prints - One
val map1 = Map((1,"One"),(2,"Two"),(3,"Three"))
val t = map1(1)

//Define a default value.Prints Oops!
val map2 = Map((1,"One"),
val t = map2(4)

//Using getOrElse method. Still prints Oops!
val map3 = Map((1,"One"),(2,"Two"),(3,"Three"))
val t = map3.getOrElse(4,"Oops!")

The above gave a good idea of searching for keys. But, in case, the requirement is to search for values here are a couple of ways

val map = Map((1,"One"),(2,"Two"),(3,"Three"))

//Returns a boolean
val b1 = map.values.exists(_ == "One")
val b2 = map.exists(_._2 =="One")

If maps is something you are interested in knowing an elaborate information is available here.

Till next time – enjoy Scala!

Leave a Comment