简体   繁体   中英

How to group by elements of tuple in Scala and map to list of new elements?

I going through some Scala exercises in order to understand better high order functions. I have the following problem, which I cant understand how to solve. I have the following list:

val input = List((1,"a"), (1,"b"), (1,"c"), (2,"d"), (2,"y"), (2,"e"), (3, "u"), (3,"a"), (3,"d"))

I want to create a Map from this list which maps each letter encountered on the input list to a list of all the numbers which were previously in the same tuple as that letter. Example output:

Map(a -> List(1,3), b->List(1), c->List(1), d->List(2,3), y->List(2), e->List(2), u->List(3)

What I have tried so far is:

val output = input.groupBy(_._2)

However this gives as output:

Map(e -> List((2,e)), y -> List((2,y)), u -> List((3,u)), a -> List((1,a), (3,a)), b -> List((1,b)), c -> List((1,c)), d -> List((2,d), (3,d)))

Could someone help me understand how I could go about solving this? I appreciate any help as I am new to functional programming

As @sinanspd said:

input
  .groupBy {
    case (numer, letter) => letter
   } map {
     case (key, list) => key -> list.map {
       case (number, letter) => number
     }
   }

// Or equivalently
input.groupBy(_._2).view.mapValues(list => list.map(_._1)).toMap

// Or even simpler if you have access to Scala 2.13
input.groupMap(_._2)(_._1)

Every time you want to transform some collection of values where the transformation is one to one, you just need a map , so in this case, you want to transform the values of the Map returned by the groupBy , which are Lists , and then you want to transform every element of those Lists to just return the first component of the tuple. So it is a map inside another map .

Also, the Scaldoc is your friend. Usually, there are many useful methods, like mapValues or groupMap .

Here is a more detailed explanation of my comment. This is what you need to do:

val output = input.groupBy(_._2).mapValues(_.map(_._1))

It is important to remember in functional programming we love pure functions. Meaning we will not have shady side effects and we like to stick to one function one purpose principle

This allows us to chain these pure functions and reason about them linearly. Why am I telling you this? While your instinct might be to look for or implement a single function to do this, don't

In this case, we first groupBy the key, and then map each value where we take the value List and map it to extract the _._1 of the tuple.

This is the best I could do, to make it sorted too , as I see the other responses are not sorted , maybe someone can improve this too:

import scala.collection.immutable.ListMap

ListMap(input.groupBy(_._2).mapValues(_.map(_._1)).toSeq.sortBy(_._1):_*)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM