GroupBy несколько столбцов в качестве ключа и суммировать несколько столбцов, как sql? - PullRequest
2 голосов
/ 08 июля 2019

Я использую 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 ]

1 голос
/ 08 июля 2019

Вы можете сделать priceLocal и priceConv кортежем, а затем поэлементно 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))
)
1 голос
/ 08 июля 2019

Вы можете использовать комбинацию 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 элементов

0 голосов
/ 09 июля 2019

Чтобы получить 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
0 голосов
/ 09 июля 2019

mapValues ​​с последующим сокращением должны сделать свое дело.Вот пример кода.

  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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...