How would I yield an immutable.Map in Scala? - scala

I have tried this but it does not work:
val map:Map[String,String] = for {
tuple2 <- someList
} yield tuple2._1 -> tuple2._2
How else would I convert a List of Tuple2s into a Map?

It couldn't be simpler:
Map(listOf2Tuples: _*)
using the apply method in Map companion object.

My First try is this:
scala> val country2capitalList = List("England" -> "London", "Germany" -> "Berlin")
country2capitalList: List[(java.lang.String, java.lang.String)] = List((England,London), (Germany,Berlin))
scala> val country2capitalMap = country2capital.groupBy(e => e._1).map(e => (e._1, e._2(0)._2))
country2capitalMap: scala.collection.Map[java.lang.String,java.lang.String] = Map(England -> London, Germany -> Berlin)
But here is the best solution:
scala> val betterConversion = Map(country2capitalList:_*)
betterConversion: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(England -> London, Germany -> Berlin)
The :_* is needed to give the compiler a hint to use the list as a varargs argument. Otherwise it will give you:
scala> Map(country2capitalList)
<console>:6: error: type mismatch;
found : List[(java.lang.String, java.lang.String)]
required: (?, ?)
Map(country2capitalList)
^
From Scala 2.8 on you can use toMap:
scala> val someList = List((1, "one"), (2, "two"))
someList: List[(Int, java.lang.String)] = List((1,one), (2,two))
scala> someList.toMap
res0: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,one), (2,two))

In 2.8, you can use the toMap method:
scala> val someList = List((1, "one"), (2, "two"))
someList: List[(Int, java.lang.String)] = List((1,one), (2,two))
scala> someList.toMap
res0: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,one), (2,two))
This will work for any collection of pairs. Note that the documentation has this to say about its duplicate policy:
Duplicate keys will be overwritten by
later keys: if this is an unordered
collection, which key is in the
resulting map is undefined.

In scala 2.8:
scala> import scala.collection.breakOut
import scala.collection.breakOut
scala> val ls = List("a","bb","ccc")
ls: List[java.lang.String] = List(a, bb, ccc)
scala> val map: Map[String,Int] = ls.map{ s => (s,s.length) }(breakOut)
map: Map[String,Int] = Map((a,1), (bb,2), (ccc,3))
scala> val map2: Map[String,Int] = ls.map{ s => (s,s.length) }.toMap
map2: Map[String,Int] = Map((a,1), (bb,2), (ccc,3))
scala>

Related

scala: how to rectify "option" type after leftOuterJoin

Given
scala> val rdd1 = sc.parallelize(Seq(("a",1),("a",2),("b",3)))
scala> val rdd2 = sc.parallelize(Seq("a",5),("c",6))
scala> val rdd3 = rdd1.leftOuterJoin(rdd2)
scala> rdd3.collect()
res: Array[(String, (Int, Option[Int]))] = Array((a,(1,Some(5))), (a,(2,Some(5))), (b,(3,None)))
We can see that the data type of "Option[Int]" in rdd3. Is there a way to rectify this so that rdd3 can be Array[String, (Int, Int)]? Suppose we can specify a value (e.g. 999) for the "None".
scala> val result = rdd3.collect()
scala> result.map(t => (t._1, (t._2._1, t._2._2.getOrElse(999))))
This should do it.

how to iterate over list of lists in scala

I want to iterate over a list[List[String]] to subset it into a list[String] and then store each list from the list of lists in a val. The val's name could be anything but it should include each list index in its name.
For example:
val x: List[ List[String]] = List(List("Nike","Apple"), List("James", "Mike"))
Desired output:
group_0 : List[String] = List(Nike, Apple)
group_1 = List[String] = List(James, Mike)
Use zipWithIndex and convert into Map[String, List[String]]. Each key will be of form group_0, group_1 etc
val map = x.zipWithIndex.map(x => s"group_${x._2}" -> x._1).toMap
Access each list using key
map("group_0")
Scala REPL
scala> x.zipWithIndex.map(x => s"group_${x._2}" -> x._1).toMap
res4: scala.collection.immutable.Map[String,List[String]] = Map(group_0 -> List(Nike, Apple), group_1 -> List(James, Mike))
scala> res4("group_0")
res6: List[String] = List(Nike, Apple)
scala> res4("group_1")
res7: List[String] = List(James, Mike)
#Manoj Kumar Dhakd idea to use toMap is better
use function zipWithIndex and zip index with your lists then use map and create a Map
val listMap=x.zipWithIndex.map(grp=>"group_"+grp._2.toString->grp._1).toMap
Display your output like below
listMap.foreach(x=>println(x._1+"="+x._2))
//output:
group_0=List(Nike, Apple)
group_1=List(James, Mike)
x.zipWithIndex.foreach{case (x,y)=>println("group_"+y+": List[String] = "+x)}
Then, in Scala REPL:
scala> val x: List[ List[String]] = List(List("Nike","Apple"), List("James", "Mike"))
x: List[List[String]] = List(List(Nike, Apple), List(James, Mike))
scala> x.zipWithIndex.foreach{case (x,y)=>println("group_"+y+": List[String] = "+x)}
group_0: List[String] = List(Nike, Apple)
group_1: List[String] = List(James, Mike)

Scala groupBy for a list

I'd like to create a map on which the key is the string and the value is the number of how many times the string appears on the list. I tried the groupBy method, but have been unsuccessful with that.
Required Answer
scala> val l = List("abc","abc","cbe","cab")
l: List[String] = List(abc, abc, cbe, cab)
scala> l.groupBy(identity).mapValues(_.size)
res91: scala.collection.immutable.Map[String,Int] = Map(cab -> 1, abc -> 2, cbe -> 1)
Suppose you have a list as
scala> val list = List("abc", "abc", "bc", "b", "abc")
list: List[String] = List(abc, abc, bc, b, abc)
You can write a function
scala> def generateMap(list: List[String], map:Map[String, Int]) : Map[String, Int] = list match {
| case x :: y => if(map.keySet.contains(x)) generateMap(y, map ++ Map(x -> (map(x)+1))) else generateMap(y, map ++ Map(x -> 1))
| case Nil => map
| }
generateMap: (list: List[String], map: Map[String,Int])Map[String,Int]
Then call the function as
scala> generateMap(list, Map.empty)
res1: Map[String,Int] = Map(abc -> 3, bc -> 1, b -> 1)
This also works:
scala> val l = List("abc","abc","cbe","cab")
val l: List[String] = List(abc, abc, cbe, cab)
scala> l.groupBy(identity).map(x => (x._1, x._2.length))
val res1: Map[String, Int] = HashMap(cbe -> 1, abc -> 2, cab -> 1)

iterate through values of given key in scala hash map

I need to check all values of a given key to see if the value is already there. With the code i have below i always get the last value added to the key. How to iterate over the entire list of values?
val map = scala.collection.mutable.HashMap.empty[Int, String]
map.put(0, "a")
map.put(0, "b")
map.put(0, "c")
map.put(0, "d")
map.put(0, "e")
map.put(0, "f")
for ((k, v) <- map) {println("key: " + k + " value: " + v)}
output:
map: scala.collection.mutable.HashMap[Int,String] = Map()
res0: Option[String] = None
res1: Option[String] = Some(a)
res2: Option[String] = Some(b)
res3: Option[String] = Some(c)
res4: Option[String] = Some(d)
res5: Option[String] = Some(e)
key: 0 value: f
res6: Unit = ()
A key is unique in a HashMap. You can't have multiple values for the same key. What you can do is have a HashMap[Int, Set[String]] and check if the value is contained inside the set, or even simpler as #TzachZohar points out, a MultiMap:
scala> import collection.mutable.{ HashMap, MultiMap, Set }
import collection.mutable.{HashMap, MultiMap, Set}
scala> val mm = new HashMap[Int, Set[String]] with MultiMap[Int, String]
mm: scala.collection.mutable.HashMap[Int,scala.collection.mutable.Set[String]] with scala.collection.mutable.MultiMap[Int,String] = Map()
scala> mm.addBinding(0, "a")
res9: <refinement>.type = Map(0 -> Set(a))
scala> mm.addBinding(0, "b")
res10: <refinement>.type = Map(0 -> Set(a, b))
scala> mm.entryExists(0, _ == "b")
res11: Boolean = true

How to create an immutable map/set from a seq?

I am try to construct immutable Sets/Maps from a Seq. I am currently doing the following:
val input: Seq[(String, Object)] = //.....
Map[String, Object]() ++ input
and for sets
val input: Seq[String] = //.....
Set[String]() ++ input
Which seems a little convoluted, is there a better way?
In Scala 2.8:
Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.
Type in expressions to have them evaluated.
Type :help for more information.
scala> val seq: Seq[(String,Object)] = ("a","A")::("b","B")::Nil
seq: Seq[(String, java.lang.Object)] = List((a,A), (b,B))
scala> val map = Map(seq: _*)
map: scala.collection.immutable.Map[String,java.lang.Object] = Map(a -> A, b -> B)
scala> val set = Set(seq: _*)
set: scala.collection.immutable.Set[(String, java.lang.Object)] = Set((a,A), (b,B))
scala>
Edit 2010.1.12
I find that there is a more simple way to create set.
scala> val seq: Seq[(String,Object)] = ("a","A")::("b","B")::Nil
seq: Seq[(String, java.lang.Object)] = List((a,A), (b,B))
scala> val set = seq.toSet
set: scala.collection.immutable.Set[(String, java.lang.Object)] = Set((a,A), (b,B))
To convert a Seq to a Map, simply call toMap on the Seq. Note that the elements of the Seq must be Tuple2 ie. (X,Y) or (X->Y)
scala> val seq: Seq[(String,String)] = ("A","a")::("B","b")::("C","c")::Nil
seq: Seq[(java.lang.String, java.lang.String)] = List((A,a), (B,b), (C,c))
scala> seq.toMap
res0: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map((A,a), (B,b), (C,c))
To convert a Seq to a Set, simply call toSet on the Seq.
scala> val seq: Seq[String] = "a"::"b"::"c"::Nil
seq: Seq[java.lang.String] = List(a, b, c)
scala> seq.toSet
res1: scala.collection.immutable.Set[java.lang.String] = Set(a, b, c)