Transformation of List[(Object1,Object2)] to Map[Object1, List[Object2]] - Scala - scala

I have a list of pairs of objects Object1 and Object2.
I want to transform this list into a Map[Object1, List[Object2]].
Until now I implemented this one:
dictionary map (w => (wordOccurrences(w), w))
groupBy(identity).mapValues(_._2).toMap
but it doesn't work.

The mapValues are Lists. You need to traverse each List in order to un-tuple each element.
You'll also need to isolate the key, "Object1", from each tuple.
No toMap required. groupBy produces a Map already.
...groupBy(_._1).mapValues(_.map(_._2))

A convenient way is to use map/case. Note the curly brackets:
val plist = List((1, 1), (2, 4), (3, 9))
plist.toMap map {case (a, b) => (a -> List (b))}

Related

how to find all possible combinations between tuples without duplicates scala

suppose I have list of tuples:
val a = ListBuffer((1, 5), (6, 7))
Update: Elements in a are assumed to be distinct inside each of the tuples2, in other words, it can be for example (1,4) (1,5) but not (1,1) (2,2).
I want to generate results of all combinations of ListBuffer a between these two tuples but without duplication. The result will look like:
ListBuffer[(1,5,6), (1,5,7), (6,7,1), (6,7,5)]
Update: elements in result tuple3 are also distinct. tuples them selves are also distinct, means as long as (6,7,1) is present, then (1,7,6) should not be in the result tuple3.
If, for example val a = ListBuffer((1, 4), (1, 5)) then the result output should be ListBuffer[(1,4,5)] in which (1,4,1) and (1,5,1) are discarded
How can I do that in Scala?
Note: I just gave an example. Usually the val a has tens of scala.Tuple2
If the individual elements are unique, as you've commented, then you should be able to flatten everything (un-tuple), get the desired combinations(), and re-tuple.
updated
val a = collection.mutable.ListBuffer((1, 4), (1, 5))
a.flatMap(t => Seq(t._1, t._2)) //un-tuple
.distinct //no duplicates
.combinations(3) //unique sets of 3
.map{case Seq(x,y,z) => (x,y,z)} //re-tuple
.toList //if you don't want an iterator

How to extract only the values from a map

I have the following Map after doing a groupBy and then partition/sliding on an List of Lists. Now i'm only interested in the values of the map, the keys are irrelevant. Basically i'm trying to extract the subset of Lists after groupBy and sliding/partition and perform additional map and reduce functions on them.
var sectionMap : Map[Int,List[List[Any]]] = Map(
1 -> List(List(1,20,"A"), List(1,40,"B")),
2 -> List(List(2,30,"A"), List(2,80,"F")),
3 -> List(List(3,80,"B"))
)
I used sectionMap.values but it returned a format like Iterable[List[List[Any]]] However I want the following type List[List[Any]]. Is there is one step function to apply to achieve the result?
List(
List(1,20,"A"),
List(1,40,"B"),
List(2,30,"A"),
List(2,80,"F"),
List(3,80,"B")
)
You can use sectionMap.values.flatten.toList.
flatten convert types like Seq[Seq[T]] to Seq[T] and toList convert Iterable to List
you need to do map.values which will gives you the List of values. As values are List of List you will get Iterable(List(List(1,20,"A"))) :Iterable[List[List[Any]]] like this so you can do flatten to make it Iterable(List(1,20,"A")): Iterable[List[Any]].
If you want it to be List[List[Any]] do .toList after flatten.
you can use:
sectionMap.values.flatten
//output List(List(1, 20, A), List(1, 40, B), List(2, 30, A), List(2, 80, F), List(3, 80, B))
Using map or flatMap or collect method on sectionMap as below:
sectionMap.map(_._2).flatten.toList
sectionMap.flatMap(_._2).toList
sectionMap.collect{case (x,y) => y}.flatten.toList
You can also use flatMap:
sectionMap.flatMap{ case (_, x) => x }.toList
It combines flattening and extraction into the same iteration.

How to find the number of (key , value) pairs in a map in scala?

I need to find the number of (key , value) pairs in a Map in my Scala code. I can iterate through the map and get an answer but I wanted to know if there is any direct function for this purpose or not.
you can use .size
scala> val m=Map("a"->1,"b"->2,"c"->3)
m: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2, c -> 3)
scala> m.size
res3: Int = 3
Use Map#size:
The size of this traversable or iterator.
The size method is from TraversableOnce so, barring infinite sequences or sequences that shouldn't be iterated again, it can be used over a wide range - List, Map, Set, etc.

Functional style in Scala to collect results from a method

I have two lists that I zip and go through the zipped result and call a function. This function returns a List of Strings as response. I now want to collect all the responses that I get and I do not want to have some sort of buffer that would collect the responses for each iteration.
seq1.zip(seq2).foreach((x: (Obj1, Obj1)) => {
callMethod(x._1, x._2) // This method returns a Seq of String when called
}
What I want to avoid is to create a ListBuffer and keep collecting it. Any clues to do it functionally?
Why not use map() to transform each input into a corresponding output ? Here's map() operating in a simple scenario:
scala> val l = List(1,2,3,4,5)
scala> l.map( x => x*2 )
res60: List[Int] = List(2, 4, 6, 8, 10)
so in your case it would look something like:
seq1.zip(seq2).map((x: (Obj1, Obj1)) => callMethod(x._1, x._2))
Given that your function returns a Seq of Strings, you could use flatMap() to flatten the results into one sequence.

Combine values with same keys in Scala

I currently have 2 lists List('a','b','a') and List(45,65,12) with many more elements and elements in 2nd list linked to elements in first list by having a key value relationship. I want combine elements with same keys by adding their corresponding values and create a map which should look like Map('a'-> 57,'b'->65) as 57 = 45 + 12.
I have currently implemented it as
val keys = List('a','b','a')
val values = List(45,65,12)
val finalMap:Map(char:Int) =
scala.collection.mutable.Map().withDefaultValue(0)
0 until keys.length map (w => finalMap(keys(w)) += values(w))
I feel that there should be a better way(functional way) of creating the desired map than how I am doing it. How could I improve my code and do the same thing in more functional way?
val m = keys.zip(values).groupBy(_._1).mapValues(l => l.map(_._2).sum)
EDIT: To explain how the code works, zip pairs corresponding elements of two input sequences, so
keys.zip(values) = List((a, 45), (b, 65), (a, 12))
Now you want to group together all the pairs with the same first element. This can be done with groupBy:
keys.zip(values).groupBy(_._1) = Map((a, List((a, 45), (a, 12))), (b, List((b, 65))))
groupBy returns a map whose keys are the type being grouped on, and whose values are a list of the elements in the input sequence with the same key.
The keys of this map are the characters in keys, and the values are a list of associated pair from keys and values. Since the keys are the ones you want in the output map, you only need to transform the values from List[Char, Int] to List[Int].
You can do this by summing the values from the second element of each pair in the list.
You can extract the values from each pair using map e.g.
List((a, 45), (a, 12)).map(_._2) = List(45,12)
Now you can sum these values using sum:
List(45, 12).sum = 57
You can apply this transform to all the values in the map using mapValues to get the result you want.
I was going to +1 Lee's first version, but mapValues is a view, and ell always looks like one to me. Just not to seem petty.
scala> (keys zip values) groupBy (_._1) map { case (k,v) => (k, (v map (_._2)).sum) }
res0: scala.collection.immutable.Map[Char,Int] = Map(b -> 65, a -> 57)
Hey, the answer with fold disappeared. You can't blink on SO, the action is so fast.
I'm going to +1 Lee's typing speed anyway.
Edit: to explain how mapValues is a view:
scala> keys.zip(values).groupBy(_._1).mapValues(l => l.map { v =>
| println("OK mapping")
| v._2
| }.sum)
OK mapping
OK mapping
OK mapping
res2: scala.collection.immutable.Map[Char,Int] = Map(b -> 65, a -> 57)
scala> res2('a') // recomputes
OK mapping
OK mapping
res4: Int = 57
Sometimes that is what you want, but often it is surprising. I think there is a puzzler for it.
You were actually on the right track to a reasonably efficient functional solution. If we just switch to an immutable collection and use a fold on a key-value zip, we get:
( Map[Char,Int]() /: (keys,values).zipped ) ( (m,kv) =>
m + ( kv._1 -> ( m.getOrElse( kv._1, 0 ) + kv._2 ) )
)
Or you could use withDefaultValue 0, as you did, if you want the final map to have that default. Note that .zipped is faster than zip because it doesn't create an intermediate collection. And a groupBy would create a number of other intermediate collections. Of course it may not be worth optimizing, and if it is you could do even better than this, but I wanted to show you that your line of thinking wasn't far off the mark.