How to transpose a map with list values in Scala - scala

How can this map of list,
Map (
"a" -> List(1, 2)
)
be transposed to this list of maps primarily using methods from the Scala libraries?
List(
Map("a" -> 1),
Map("a" -> 2)
)
I can code a solution myself but I am more interested in using library functionality so the preferred solution should use the Scala library where possible while remaining compact and moderately legible.
This second example illustrates the required transformation with a map with more than one entry.
From this,
Map (
10 -> List("10a", "10b", "10c"),
29 -> List("29a", "29b", "29c")
)
to this,
List(
Map(
10 -> "10a",
29 -> "29a"),
Map(
10 -> "10b",
29 -> "29b"),
Map(
10 -> "10c",
29 -> "29c")
)
It can be assumed that all values are lists of the same size.
Optionally the solution could handle the case where the values are empty lists but that is not required. If the solution supports empty list values then this input,
Map (
"a" -> List()
)
should result in List().

val m = Map (
10 -> List("10a", "10b", "10c"),
29 -> List("29a", "29b", "29c")
)
m.map{ case (k, vs) =>
vs.map(k -> _)
}.toList.transpose.map(_.toMap)
Note that this also handles your "empty list" case

Related

Map function returns value inside Iterable List ? Scala

I have a question in regards Scala map function.
Why does the map function return the result wrapped in a List collection?
Example
val exMap = Map("k" -> Map("kate" -> 34))
exMap.map{
case (k,v) => println(v.map(_._2))
}
Why this gives as a output : List(34)
instead of 34 ?
Here v represents the internal
Map("kate" -> 34)
which could contain as many values, example
Map("kate" -> 34, "sam" -> 43)
and in above code snippet with variable "v" we are representing values of this interval map which comes out to be List(34, 43)
Here in your example map contains only single key-value pair but can have as many key value pairs hence return of fetching all values is List(values)
val exMap = Map("k" -> Map("kate" -> 34),"a" -> Map("abe" -> 31))
exMap.map{
case ( k :String,v : Map[String,Int]) => println(
v // Map("kate" -> 34) , Map("abe" -> 31)
.map(
_._2 // 34, 31
)
.foreach(println(_)) //place to retrieve each element and perform action over it
)
} // by default map will collect all the returning value to a single list

How to get the possible pair combinaisons of values of a hashmap Scala

I have a hashmap as follows :
val hm : HashMap[Int, List[String]] =
HashMap(
1 -> List("Eat", "Drink","Sleep", "work"),
2 -> List("Eat", "Sleep","Dance"),
3 -> List("Write", "Print","Dance")
)
I want to retrieve the possible pairs of this hashmap's values and return each pair separately in a list
I'm using the combinaisons function as
hm.mapValues(_.combinations(2).toList)
The result is :
Map(1-> List(List(Eat, Drink), List(Eat, Sleep), List(Eat, work), List(Drink, Sleep), List(Drink, work), List(Sleep, work)), 2-> List(List(Eat, Sleep), List(Eat, Dance), List(Sleep, Dance)), 3 -> List(List(Write, Print), List(Write, Dance), List(Print, Dance)))
yet the expected result should be three lists
List(List("Eat", "Drink","Sleep", "work"),List("Eat", "Sleep","Dance"))
List( List("Eat", "Drink","Sleep", "work"),List("Write", "Print","Dance"))
List(List("Eat", "Sleep","Dance"), List("Write", "Print","Dance"))
What am I missing
use only values of your map:
hm.values.toList.combinations(2).toList
https://scalafiddle.io/sf/ZGbHC4c/0

Scala - map function - Only returned last element of a Map

I am new to Scala and trying out the map function on a Map.
Here is my Map:
scala> val map1 = Map ("abc" -> 1, "efg" -> 2, "hij" -> 3)
map1: scala.collection.immutable.Map[String,Int] =
Map(abc -> 1, efg -> 2, hij -> 3)
Here is a map function and the result:
scala> val result1 = map1.map(kv => (kv._1.toUpperCase, kv._2))
result1: scala.collection.immutable.Map[String,Int] =
Map(ABC -> 1, EFG -> 2, HIJ -> 3)
Here is another map function and the result:
scala> val result1 = map1.map(kv => (kv._1.length, kv._2))
result1: scala.collection.immutable.Map[Int,Int] = Map(3 -> 3)
The first map function returns all the members as expected however the second map function returns only the last member of the Map. Can someone explain why this is happening?
Thanks in advance!
In Scala, a Map cannot have duplicate keys. When you add a new key -> value pair to a Map, if that key already exists, you overwrite the previous value. If you're creating maps from functional operations on collections, then you're going to end up with the value corresponding to the last instance of each unique key. In the example you wrote, each string key of the original map map1 has the same length, and so all your string keys produce the same integer key 3 for result1. What's happening under the hood to calculate result1 is:
A new, empty map is created
You map "abc" -> 1 to 3 -> 3 and add it to the map. Result now contains 1 -> 3.
You map "efg" -> 2 to 3 -> 2 and add it to the map. Since the key is the same, you overwrite the existing value for key = 3. Result now contains 2 -> 3.
You map "hij" -> 3 to 3 -> 3 and add it to the map. Since the key is the same, you overwrite the existing value for key = 3. Result now contains 3 -> 3.
Return the result, which is Map(3 -> 3)`.
Note: I made a simplifying assumption that the order of the elements in the map iterator is the same as the order you wrote in the declaration. The order is determined by hash bin and will probably not match the order you added elements, so don't build anything that relies on this assumption.

Update values of Map

I have a Map like:
Map("product1" -> List(Product1ObjectTypes), "product2" -> List(Product2ObjectTypes))
where ProductObjectType has a field usage. Based on the other field (counter) I have to update all ProductXObjectTypes.
The issue is that this update depends on previous ProductObjectType, and I can't find a way to get previous item when iterating over mapValues of this map. So basically, to update current usage I need: CurrentProduct1ObjectType.counter - PreviousProduct1ObjectType.counter.
Is there any way to do this?
I started it like:
val reportsWithCalculatedUsage =
reportsRefined.flatten.flatten.toList.groupBy(_._2.product).mapValues(f)
but I don't know in mapValues how to access previous list item.
I'm not sure if I understand completely, but if you want to update the values inside the lists based on their predecessors, this can generally be done with a fold:
case class Thing(product: String, usage: Int, counter: Int)
val m = Map(
"product1" -> List(Thing("Fnord", 10, 3), Thing("Meep", 0, 5))
//... more mappings
)
//> Map(product1 -> List(Thing(Fnord,10,3), Thing(Meep,0,5)))
m mapValues { list => list.foldLeft(List[Thing]()){
case (Nil, head) =>
List(head)
case (tail, head) =>
val previous = tail.head
val current = head copy (usage = head.usage + head.counter - previous.counter)
current :: tail
} reverse }
//> Map(product1 -> List(Thing(Fnord,10,3), Thing(Meep,2,5)))
Note that regular map is an unordered collection, you need to use something like TreeMap to have predictable order of iteration.
Anyways, from what I understand you want to get pairs of all values in a map. Try something like this:
scala> val map = Map(1 -> 2, 2 -> 3, 3 -> 4)
scala> (map, map.tail).zipped.foreach((t1, t2) => println(t1 + " " + t2))
(1,2) (2,3)
(2,3) (3,4)

How to convert Map[String,Seq[String]] to Map[String,String]

I have a Map[String,Seq[String]] and want to basically covert it to a Map[String,String] since I know the sequence will only have one value.
Someone else already mentioned mapValues, but if I were you I would do it like this:
scala> val m = Map(1 -> Seq(1), 2 -> Seq(2))
m: scala.collection.immutable.Map[Int,Seq[Int]] = Map(1 -> List(1), 2 -> List(2))
scala> m.map { case (k,Seq(v)) => (k,v) }
res0: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2)
Two reasons:
The mapValues method produces a view of the result Map, meaning that the function will be recomputed every time you access an element. Unless you plan on accessing each element exactly once, or you only plan on accessing a very small percentage of them, you don't want that recomputation to take place.
Using a case with (k,Seq(v)) ensures that an exception will be thrown if the function ever sees a Seq that doesn't contain exactly one element. Using _(0) or _.head will throw an exception if there are zero elements, but will not complain if you had more than one, which will likely result in mysterious bugs later on when things go missing without errors.
You can use mapValues().
scala> Map("a" -> Seq("aaa"), "b" -> Seq("bbb"))
res0: scala.collection.immutable.Map[java.lang.String,Seq[java.lang.String]] = M
ap(a -> List(aaa), b -> List(bbb))
scala> res0.mapValues(_(0))
res1: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(a
-> aaa, b -> bbb)
I think I got it by doing the following:
mymap.flatMap(x => Map(x._1 -> x._2.head))
Yet another suggestion:
m mapValues { _.mkString }
This one's agnostic to whether the Seq has multiple elements -- it'll just concatenate all the strings together. If you're concerned about the recomputation of each value, you can make it happen up-front:
(m mapValues { _.mkString }).view.force