Gabriel Asman
Gabriel Asman

Reputation: 181

Scala groupBy + mapValues + map back to initial format. Is there a better way

In a project I'm working on, I often find myself doing the following pattern.

Given a case class X(a: A, b: B, c:C, d: Int), and a list of such X's xs: List[X], I want to do the database equivalent of grouping by a,b,c, while summing by d, and having the return type as List[X].

What I usually end up doing is

xs.groupBy{case X(a,b,c,d) => (a,b,c)).mapValues(_.sum).map(((a,b,c),d)) => X(a,b,c,d))

My question, is there a better/clearer/more idiomatic way of doing this with either the scala standard library or Scalaz (If d is of an arbitrary type with a Monoid instance perhaps)?

Upvotes: 4

Views: 418

Answers (1)

Kamil Banaszczyk
Kamil Banaszczyk

Reputation: 1153

I think I know what you are trying to achieve, i've found a shorter way to achieve this, you don't have to use mapValues, and then map, instead you can do everything with one map, like this:

case class X(a: String, b: String, c: String, d: Int){
  def +(that: X) = X(a,b,c, d+that.d)
}

val list = List(X("1","2","3",4),X("1","2","3",5),X("11","22","33",6),X("11","22","33",9))

list.groupBy{
  case X(a,b,c,d) => (a,b,c)}.map{ case (k,v) => X(k._1, k._2, k._3, v.reduce(_ + _).d)}

If you can use sum with your class it will be shorter and more cleaner, but reduce isn't that bad either.

Upvotes: 0

Related Questions