Friday, 29 December 2017

Introduction to Scala - XV

We continue the journey on Scala on the topic of Maps in this post. For all the work in this post, we will use Read-Evaluate-Print-Loop Scala interpreter. Some familiarity with Java will be of great help in understanding Scala. In this post, we will look at how Maps are defined along with some features of Maps in Scala.

Map is a collection that has elements in the form of a pair of sub elements: one is a key and the other is a value. Keys have to be unique while values need not.

We can define maps as shown below:

1) An empty map that has a keys of type String and values of type Int:

val Map0: Map[String,Int] = Map()

The results are shown below:

scala> val Map0: Map[String,Int] = Map()
Map0: Map[String,Int] = Map()


2) A Map initialized with key, value pairs:

val Map1: Map[String,Int] = Map("King" -> 24000, "Kochhar" -> 17000, "De Haan" -> 17000)

The results are shown below:

scala> val Map1: Map[String,Int] = Map("King" -> 24000, "Kochhar" -> 17000, "De Haan" -> 17000)
Map1: Map[String,Int] = Map(King -> 24000, Kochhar -> 17000, De Haan -> 17000)


In the above case, to show the association between employee name and the corresponding salary, an arrow symbol, -> is used. Another way to create a Map is shown where name and salary and together in parentheses. We are using an mix of both below:

val Map2: Map[String,Int] = Map(("De Haan" -> 17000),("Hunold", 9000), ("Ernst", 6000), ("Austin", 4800))

The results are shown below:

scala> val Map2: Map[String,Int] = Map(("De Haan" -> 17000),("Hunold", 9000), ("Ernst", 6000), ("Austin", 4800))
Map2: Map[String,Int] = Map(De Haan -> 17000, Hunold -> 9000, Ernst -> 6000, Austin -> 4800)


Thus, we have created two maps. Like Sets, there are the mutable and immutable Maps.

There are many operations that can be performed that are common with Arrays, Vectors and Sets. In this post, we will look at some operations.

1) + : Adds one or more key, value pairs

scala> Map1
res81: Map[String,Int] = Map(King -> 24000, Kochhar -> 17000, De Haan -> 17000)

scala> Map1 + (("AddKey" -> 100))
res82: scala.collection.immutable.Map[String,Int] = Map(King -> 24000, Kochhar -> 17000, De Haan -> 17000, AddKey -> 100)

scala> Map1
res83: Map[String,Int] = Map(King -> 24000, Kochhar -> 17000, De Haan -> 17000)


scala> Map1 + (("AddKey" -> 100),("AddMoreKey",1000))
res84: scala.collection.immutable.Map[String,Int] = Map(King -> 24000, AddMoreKey -> 1000, Kochhar -> 17000, De Haan -> 17000, AddKey -> 100)

scala> Map1
res85: Map[String,Int] = Map(King -> 24000, Kochhar -> 17000, De Haan -> 17000)


2) ++ : Adds two maps

scala> Map1 ++ Map2
res86: scala.collection.immutable.Map[String,Int] = Map(King -> 24000, Ernst -> 6000, Kochhar -> 17000, De Haan -> 17000, Austin -> 4800, Hunold -> 9000)


3) - : Removes a key value when a key is passed

scala> Map1 - ("King")
res91: scala.collection.immutable.Map[String,Int] = Map(Kochhar -> 17000, De Haan -> 17000) 


4) apply : Returns value associated with a key

scala> Map1 apply ("King")
res93: Int = 24000


5) filter: filters based on both key and value criteria 

scala> Map1.filter((test:(String,Int)) => (test._1).startsWith("De"))
res114: scala.collection.immutable.Map[String,Int] = Map(De Haan -> 17000)


scala> Map1.filter((test:(String,Int)) => test._2 >=19000)
res118: scala.collection.immutable.Map[String,Int] = Map(King -> 24000)


scala> Map1.filter((test:(String,Int)) => (test._1).startsWith("Ki") & test._2 >=19000)
res119: scala.collection.immutable.Map[String,Int] = Map(King -> 24000)


6) filterKeys : filters based on key

scala> Map1.filterKeys(_.startsWith("De"))
res96: scala.collection.immutable.Map[String,Int] = Map(De Haan -> 17000)


7) getOrElse : Based on key, gets a value or sets a default if no corresponding key

scala> Map1.getOrElse("King",100000)
res129: Int = 24000

scala> Map1.getOrElse("Queen",100000)
res130: Int = 100000


8) isDefinedAt : Returns a boolean based on presence of a key

scala> Map1.isDefinedAt("King")
res131: Boolean = true


9) keySet: Returns a Set of all keys

scala> Map1.keySet
res132: scala.collection.immutable.Set[String] = Set(King, Kochhar, De Haan)


10) keys : Returns all keys

scala> Map1.keys
res133: Iterable[String] = Set(King, Kochhar, De Haan)


11) keysIterator : Returns an iterator for keys

scala> val Map1_keysIterator1 = Map1.keysIterator
Map1_keysIterator1: Iterator[String] = non-empty iterator

scala> while (Map1_keysIterator1.hasNext) {
     | println(Map1_keysIterator1.next())
     | }
King
Kochhar
De Haan


12)  mapValues: Applies a function on values. We are halving the value as shown below:

scala> Map1.mapValues(n => n/2)
res21: scala.collection.immutable.Map[String,Int] = Map(King -> 12000, Kochhar -> 8500, De Haan -> 8500)


13) sliding: Returns maps in sequence based on sliding window

scala> val Map1_sliding1 = Map1.sliding(2)
Map1_sliding1: Iterator[scala.collection.immutable.Map[String,Int]] = non-empty iterator

scala> while (Map1_sliding1.hasNext) {
     | println(Map1_sliding1.next())
     | }
Map(King -> 24000, Kochhar -> 17000)
Map(Kochhar -> 17000, De Haan -> 17000)


14)  valuesIterator: Similar to keysIterator but based on values

scala> val Map1_valuesIterator1 = Map1.valuesIterator
Map1_valuesIterator1: Iterator[Int] = non-empty iterator

scala> while (Map1_valuesIterator1.hasNext) {
     | println(Map1_valuesIterator1.next())
     | }
24000
17000
17000


15)  zipAll : Combines two maps with corresponding key, value pairs. If any pairs fall short, then, these are picked up from the next default values

scala> Map1
res13: Map[String,Int] = Map(King -> 24000, Kochhar -> 17000, De Haan -> 17000)

scala> Map2
res14: Map[String,Int] = Map(De Haan -> 17000, Hunold -> 9000, Ernst -> 6000, Austin -> 4800)

scala> Map1.zipAll(Map2,("test1",100),("test2",1000))
res15: scala.collection.immutable.Map[(String, Int),(String, Int)] = Map((King,24000) -> (De Haan,17000), (Kochhar,17000) -> (Hunold,9000), (De Haan,17000) -> (Ernst,6000), (test1,100) -> (Austin,4800))

 
In the above case, Map1 has fewer key, value pairs than Map2. So, the default value is set in last case

This concludes the discussion of Maps in Scala