GappedState
GappedState

Reputation: 19

Scala - Mapping one key to multiple values of different type

So I am trying to play around with data in Scala. I've hit a roadblock now. I'm reading a text file into the program that contains a list, made a case class to read each header. I've managed to do a mapping of (String, String) to a double, but I would like this instead to be mapping a string to a (string, double). The relevant code is here:

def averageofactions (): Map[(String,String),  Double] = {

  datafile.groupBy(d => (d.user, d.typeofaction))
.mapValues(averageof => averageof.map(_.amount).sum /averageof.length)
 }

Which gives me what I want (the average amount of a particular action by a particular user) but formatted so that it gives (UserID, Action) -> Average, whereas I simply want a list like

UserID1:

Action1 -> Average

Action2 -> Average

and so on. I understand that probably the best way to do this is by changing it such that I return Map[String, (String,Double)], or perhaps a multimap/hashmap, but I'm unsure how to go about this. I tried:

def modifiedaverage (): Map[String, (List[String], Double)] = {

  datafile.groupBy(d => (d.user))
.mapValues(averageof => (averageof.map(_.typeofaction),     averageof.map(_.amount).sum/averageof.length))

}

but the output here is totally strange. How can I rewrite this function to give me what I want?

Upvotes: 0

Views: 1555

Answers (1)

Tzach Zohar
Tzach Zohar

Reputation: 37822

If you want the output to be of type Map[String, Map[String, Double]] (map of maps), you can group by actionoftype on each result of grouping by user:

def averageofactions(): Map[String, Map[String, Double]] = {
  datafile.groupBy(_.user)
    .mapValues(_.groupBy(_.typeofaction)
      .mapValues(averageof => averageof.map(_.amount).sum /averageof.length))
}

Alternatively, if you want to "flatten" this into a sequence (and not a map) of (String, String, Double) tuples, you can:

def averageofactions(): Seq[(String, String, Double)] = {
  datafile.groupBy(averageof => (averageof.user, averageof.typeofaction))
    .mapValues(averageof => averageof.map(_.amount).sum /averageof.length)
    .map { case ((user, action), avg) => (user, action, avg) }.toSeq
}

Upvotes: 2

Related Questions