unpivot a map/list/tuples using scala - scala

I have something like this:
val m1 = Map(A -> List(("a","b"),("c","d"),("e","f")))
I want the result to be :
(Map(A -> List("a","b")), Map(A -> List ("c","d")), Map(A -> List("e","f")))
could anyone help?
Thanks

It's hard to tell what exactly you are trying to do, but here is a way to convert m1 to the desired structure:
val m1 = Map("A" -> List(("a","b"),("c","d"),("e","f")))
m1.toList.flatMap { case (key, tuple) =>
tuple.map(v => Map(key -> List(v._1, v._2)))
}

Related

Scala assign value to Map of Map

Consider var myMap = Map[String,Map[String,Map[String,String]]]().
1) I tried to add entries to this variable as shown below but was unsuccessful: myMap = myMap + ("a" -> ("b1" -> ("c" -> "d", "e" -> "f"))) How may I fix that?
2) Assuming we are done with step 1 above, how can we add add another sub-map somewhere in the structure; say myMap = myMap + ("a" -> ("b2" -> ("g" -> "h")))?
The final result should be something similar to the structure below:
a:{
b1:{
c:d,
e:f
},
b2:{
g:h
}
}
This is going to be easier to do with a mutable collection rather than a mutable variable.
import collection.mutable.Map
val myMap = Map[String,Map[String,Map[String,String]]]()
myMap.update("a", Map("b1" -> Map("c" -> "d", "e" -> "f")))
myMap("a").update("b2", Map("g" -> "h"))
//Map(a -> Map(b2 -> Map(g -> h), b1 -> Map(c -> d, e -> f)))

Functional Programming: Get new Map from existing Map with changed value

I have one map like
val strMap = Map[String, String]("a" -> "a1", "b" -> "b1") // Map(a -> a1, b -> b1)
and I want to create another map with same key but different value, based on value in strMap. For example
case class Data(data: String) {}
var dataMap = scala.collection.mutable.Map[String, Data]()
strMap.foreach (keyVal => {dataMap(keyVal._1) = Data(keyVal._2)})
val dataMapToUse = dataMap.toMap // Map(a -> Data(a1), b -> Data(b1))
but writing this in imperative style is causing issue like creation of "var dataMap", though I want to get immutable map. Because of this, I have to call toMap to get same.
How can I achieve same in functional programming?
Scala Version: 2.11
Why not simply use,
val dataMapToUse = strMap.map{case(k,v) =>(k -> Data(v))}

How to combine all the values with the same key in Scala?

I have a map like :
val programming = Map(("functional", 1) -> "scala", ("functional", 2) -> "perl", ("orientedObject", 1) -> "java", ("orientedObject", 2) -> "C++")
with the same first element of key appearing multiple times.
How to regroup all the values corresponding to the same first element of key ? Which would turn this map into :
Map("functional" -> List("scala","perl"), "orientedObject" -> List("java","C++"))
UPDATE: This answer is based upon your original question. If you need the more complex Map definition, using a tuple as the key, then the other answers will address your requirements. You may still find this approach simpler.
As has been pointed out, you can't actually have multiple keys with the same value in a map. In the REPL, you'll note that your declaration becomes:
scala> val programming = Map("functional" -> "scala", "functional" -> "perl", "orientedObject" -> "java", "orientedObject" -> "C++")
programming: scala.collection.immutable.Map[String,String] = Map(functional -> perl, orientedObject -> C++)
So you end up missing some values. If you make this a List instead, you can get what you want as follows:
scala> val programming = List("functional" -> "scala", "functional" -> "perl", "orientedObject" -> "java", "orientedObject" -> "C++")
programming: List[(String, String)] = List((functional,scala), (functional,perl), (orientedObject,java), (orientedObject,C++))
scala> programming.groupBy(_._1).map(p => p._1 -> p._2.map(_._2)).toMap
res0: scala.collection.immutable.Map[String,List[String]] = Map(functional -> List(scala, perl), orientedObject -> List(java, C++))
Based on your edit, you have a data structure that looks something like this
val programming = Map(("functional", 1) -> "scala", ("functional", 2) -> "perl",
("orientedObject", 1) -> "java", ("orientedObject", 2) -> "C++")
and you want to scrap the numerical indices and group by the string key. Fortunately, Scala provides a built-in that gets you close.
programming groupBy { case ((k, _), _) => k }
This will return a new map which contains submaps of the original, grouped by the key that we return from the "partial" function. But we want a map of lists, so let's ignore the keys in the submaps.
programming groupBy { case ((k, _), _) => k } mapValues { _.values }
This gets us a map of... some kind of Iterable. But we really want lists, so let's take the final step and convert to a list.
programming groupBy { case ((k, _), _) => k } mapValues { _.values.toList }
You should try the .groupBy method
programming.groupBy(_._1._1)
and you will get
scala> programming.groupBy(_._1._1)
res1: scala.collection.immutable.Map[String,scala.collection.immutable.Map[(String, Int),String]] = Map(functional -> Map((functional,1) -> scala, (functional,2) -> perl), orientedObject -> Map((orientedObject,1) -> java, (orientedObject,2) -> C++))
you can now "clean" by doing something like:
scala> res1.mapValues(m => m.values.toList)
res3: scala.collection.immutable.Map[String,List[String]] = Map(functional -> List(scala, perl), orientedObject -> List(java, C++))
Read the csv file and create a map that contains key and list of values.
val fileStream = getClass.getResourceAsStream("/keyvaluepair.csv")
val lines = Source.fromInputStream(fileStream).getLines
var mp = Seq[List[(String, String)]]();
var codeMap=List[(String, String)]();
var res = Map[String,List[String]]();
for(line <- lines )
{
val cols=line.split(",").map(_.trim())
codeMap ++= Map(cols(0)->cols(1))
}
res = codeMap.groupBy(_._1).map(p => p._1 -> p._2.map(_._2)).toMap
Since no one has put in the specific ordering he asked for:
programming.groupBy(_._1._1)
.mapValues(_.toSeq.map { case ((t, i), l) => (i, l) }.sortBy(_._1).map(_._2))

How to use Reduce on Scala

I am using scala to implement an algorithm. I have a case where I need to implement such scenario:
test = Map(t -> List((t,2)), B -> List((B,3), (B,1)), D -> List((D,1)))
I need to some the second member of every common tuples.
The desired result :
Map((t,2),(B,4),(D,1))
val resReduce = test.foldLeft(Map.empty[String, List[Map.empty[String, Int]]){(count, tup) => count + (tup -> (count.getOrElse(tup, 0) + 1))
I am trying to use "Reduce", I have to go through every group I did and sum their second member. Any idea how to do that.
If you know that all lists are nonempty and start with the same key (e.g. they were produced by groupBy), then you can just
test.mapValues(_.map(_._2).sum).toMap
Alternatively, you might want an intermediate step that allows you to perform error-checking:
test.map{ case(k,xs) =>
val v = {
if (xs.exists(_._1 != k)) ??? // Handle key-mismatch case
else xs.reduceOption((l,r) => l.copy(_2 = l._2 + r._2))
}
v.getOrElse(??? /* Handle empty-list case */)
}
You could do something like this:
test collect{
case (key, many) => (key, many.map(_._2).sum)
}
wherein you do not have to assume that the list has any members. However, if you want to exclude empty lists, add a guard
case (key, many) if many.nonEmpty =>
like that.
scala> val test = Map("t" -> List(("t",2)), "B" -> List(("B",3), ("B",1)), "D" -> List(("D",1)))
test: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(t -> List((t,2)), B -> List((B,3), (B,1)), D -> List((D,1)))
scala> test.map{case (k,v) => (k, v.map(t => t._2).sum)}
res32: scala.collection.immutable.Map[String,Int] = Map(t -> 2, B -> 4, D -> 1)
Yet another approach, in essence quite similar to what has already been suggested,
implicit class mapAcc(val m: Map[String,List[(String,Int)]]) extends AnyVal {
def mapCount() = for ( (k,v) <- m ) yield { (k,v.map {_._2}.sum) }
}
Then for a given
val test = Map("t" -> List(("t",2)), "B" -> List(("B",3), ("B",1)), "D" -> List(("D",1)))
a call
test.mapCount()
delivers
Map(t -> 2, B -> 4, D -> 1)

Creating a Map of a Map

I'm very new to Scala so I apologize for asking stupid questions. I'm coming from scripting languages such as python, perl, etc. that let you get away w/ a lot.
How do I create a map which contains a map? In Python, I can create the following:
{ 'key': { 'data': 'value' }}
...or in perl
%hash = ( 'key' => ( 'data' => 'value' ));
Also, what is the difference between Map and scala.collection.mutable/immutable.Map, or is there a difference?
A slightly more simple way to create a map of maps:
Map("german" -> Map(1 -> "eins", 2 -> "two"),
"english" -> Map(1 -> "one", 2 -> "two"))
This way you do not have to specify the type explicitly. Regarding the difference between immutable and mutable: Once you have created an immutable map, you cannot change it. You can only create a new map based on the old one with some of the elements changed.
In scala you can create a Map, if you want to fill it at creation, this way:
val mapa = Map(key1 -> value1, key2 -> value2)
Another way would be:
var mapb = Map[Key, Value]()
mapb += key1 -> value1
A map of maps could be created this way:
var mapOfMaps = Map[String, Map[Int, String]]()
mapOfMaps += ("english" -> Map(1 -> "one", 2 -> "two"))
mapOfMaps += ("french" -> Map(1 -> "un", 2 -> "deux"))
mapOfMaps += ("german" -> Map(1 -> "eins", 2 -> "zwei"))
Note that the inner Map is immutable in this example.