how to iterate over list of lists in scala - 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)

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.

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 simplify nested map calls?

Suppose I have a few nested functors, e.g. List[Option[Int]] and need to call the map of the most inner one.
Now I am using nested maps:
scala> val opts: List[Option[Int]] = List(Some(0), Some(1))
opts: List[Option[Int]] = List(Some(0), Some(1))
scala> opts.map(o => o.map(_ + 1))
res0: List[Option[Int]] = List(Some(1), Some(2))
What if I have 3 nesting levels, for instance ?
Is there any simple alternative to nested maps ?
Yes, this is possible with scalaz.Functor:
scala> import scalaz.Functor
import scalaz.Functor
scala> import scalaz.std.list._
import scalaz.std.list._
scala> import scalaz.std.option._
import scalaz.std.option._
scala> Functor[List].compose[Option].map(List(some(0), some(1)))(_ + 1)
res1: List[Option[Int]] = List(Some(1), Some(2))
However, this is longer than to simply call map with a nested map. If you often map nested structures, you can create helper functions:
def map2[F[_], G[_], A, B](fg: F[G[A]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G]): F[G[B]] =
F0.map(fg)(g => G0.map(g)(f))
def map3[F[_], G[_], H[_], A, B](fg: F[G[H[A]]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G], H0: Functor[H]): F[G[H[B]]] =
F0.map(fg)(g => G0.map(g)(h => H0.map(h)(f)))
...
Usage:
scala> map2(List(some(0), some(1)))(_ + 1)
res3: List[Option[Int]] = List(Some(1), Some(2))
scala> map3(List(some(some(0)), some(some(1))))(_ + 1)
res4: List[Option[Option[Int]]] = List(Some(Some(1)), Some(Some(2)))
If you have a lot of nested functors and you don't want to flatten them (i.e. they're not monads or you don't want to use them as monads) - then lenses may help. There is quicklens implementation, which supports traversable lenses : http://www.warski.org/blog/2015/03/quicklens-traversing-options-and-lists/.
Example (sorry didn't try to compile it):
modify(opts)(_.each.each).using(_ + 1)
Anyway, you have to specify nesting level, but you don't have to nest functions here. And it's enough to specify it once, like (conceptual example, didn't check):
def md2[T]: (l: List[Option[T]]) => modify(l)(_.each.each)
md2[Int](opts).using(_ + 1)
From the question I understood that you are tying to prune the list iterator e.i. remove upper levels of list in that case you can use flatten which convert list of lists into a single list.
I will be removing few layers of list using flatten
Code:-
val lists = List(
List(
List(
List("1"),List("2")
),
List(
List("3"),List("4")
) ,
List(
List("a"),List("b")
),
List(
List("c"),List("d")
)
)
)
val innerVal = lists.flatten.foreach(println)
results :-
List(List(1), List(2))
List(List(3), List(4))
List(List(a), List(b))
List(List(c), List(d))

How would I yield an immutable.Map in 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>

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)