GroupBy将多个列作为键并汇总多个列(如sql)?

时间:2019-07-08 19:59:32

标签: scala group-by

我正在使用Scala 2.12。

我有一个案例类,如下:

case class MyClass(date: java.util.Date, book: String, priceLocal: Double, priceConv: Double)

我可以根据日期和书籍分组。

例如,用于:

val listOfMyClass = List(
  MyClass(20190708, "book1", 100, 120),
  MyClass(20190708, "book1", 200, 220),
  MyClass(20190708, "book2", 50, 60),
  MyClass(20190708, "book2", 60, 70)
)

val groupedData = listOfMyClass.groupBy(t => (t.date, t.book))

我希望数据像SQL中一样:

(20190708, "book1", 300, 340)
(20190708, "book2", 110, 130)

我能够映射和累加一列,但不能同时使用这两列。

val groupedDataSum = listOfMyClass.groupBy(t => (t.date, t.book)).mapValues(_.map(_.priceLocal).sum)

但是如何将第二列也用作总和?

4 个答案:

答案 0 :(得分:1)

您可以混合使用groupBy(按日期和书籍分组元素)和reduce来累积分组值:

// val list = List(
//   MyClass(Date(2019, 7, 8), "book1", 100, 120),
//   MyClass(Date(2019, 7, 8), "book1", 200, 220),
//   MyClass(Date(2019, 7, 8), "book2", 50, 60),
//   MyClass(Date(2019, 7, 8), "book2", 60, 70)
// )
list
  .groupBy { case MyClass(date, book, _, _) => (date, book) }
  .mapValues { values =>
    values
      .map { case MyClass(_, _, priceLocal, priceConv) => (priceLocal, priceConv) }
      .reduce((x, y) => (x._1 + y._1, x._2 + y._2))
  }
  .map { case ((date, book), (priceLocal, priceConv)) =>
    (date, book, priceLocal, priceConv)
  }
// List(
//   (Date(2019, 7, 8), "book1", 300, 340),
//   (Date(2019, 7, 8), "book2", 110, 130)
// )

此:

  • 按日期和书籍(groupBy)分组字符

  • 通过以下方式映射每个分组的值(mapValues):

    • 将值映射为价格元组
    • 并通过部分求和来减少这些元组
  • 将元组(日期,书)到元组(价格,价格)的地图映射到4个元素的元组

答案 1 :(得分:1)

您可以将priceLocalpriceConv做成一个元组,然后按元素进行reduce来汇总各个元组元素:

listOfMyClass.groupBy(t => (t.date, t.book)).mapValues(
  _.map(s => (s.priceLocal, s.priceConv)).
    reduce((acc, x) => (acc._1 + x._1, acc._2 + x._2))
)

答案 2 :(得分:0)

mapValues后跟reduce应该可以解决问题。这是示例代码。

  val grouped = listOfMyClass.groupBy(t => (t.date, t.book))
    .mapValues(lst => lst.reduce((m1, m2) => 
      MyClass(m1.date, m1.book, m1.priceLocal + m2.priceLocal, m1.priceConv + m2.priceConv))).values

这将使迭代器返回到简化的MyClass实例列表。

答案 3 :(得分:0)

要获得所需的类似SQL的输出,只需对通过Map[(Date,String],(Double, Double)]mapValues操作生成的reduce做最后一个映射。

listOfMyClass groupBy(a => (a.date, a.book)) 
mapValues(a => a.map(e => (e.priceConv, e.priceLocal)) reduce((a,b) => (a._1+b._1, a._2+b._2)))
map (x => (x._1._1, x._1._2, x._2._1, x._2._1)) //final map will give you the SQL-type output you were looking for