groupby scala字符串列表

时间:2018-05-25 08:50:10

标签: scala group-by

我在计算Scala中具有相同标题的元素总和时遇到问题(在这种情况下是我的密钥)。

目前我的输入可以描述为:

val listInput1 = 
  List(
    "itemA,CATA,2,4 ",
    "itemA,CATA,3,1 ",
    "itemB,CATB,4,5",
    "itemB,CATB,4,6"
   )

val listInput2 = 
  List(
    "itemA,CATA,2,4 ",
    "itemB,CATB,4,5",
    "itemC,CATC,1,2"
  )

输入中列表所需的输出应为

val listoutput1 = 
  List(
    "itemA,CATA,5,5 ",
    "itemB,CATB,8,11"
  )

val listoutput2 =
  List(
    "itemA , CATA, 2,4 ",
    "itemB,CATB,4,5",
    "itemC,CATC,1,2"
  )

我写了以下函数:

def sumByTitle(listInput: List[String]): List[String] =      
  listInput.map(_.split(",")).groupBy(_(0)).map { 
    case (title, features) => 
       "%s,%s,%d,%d".format(
         title,
         features.head.apply(1),
         features.map(_(2).toInt).sum,
         features.map(_(3).toInt).sum)}.toList

它不会给我预期的结果,因为它改变了行的顺序。

我该如何解决?

3 个答案:

答案 0 :(得分:0)

如果您只对排序感兴趣,可以直接返回sorted列表:

val listInput1 = 
  List(
    "itemA , CATA, 2,4 ",
    "itemA , CATA, 3,1 ",
    "itemB,CATB,4,5",
    "itemB,CATB,4,6"
   )

val listInput2 = 
  List(
    "itemA , CATA, 2,4 ",
    "itemB,CATB,4,5",
    "itemC,CATC,1,2"
  )

def sumByTitle(listInput: List[String]): List[String] =      
  listInput.map(_.split(",")).groupBy(_(0)).map { 
    case (title, features) => 
       "%s,%s,%d,%d".format(
         title,
         features.head.apply(1),
         features.map(_(2).trim.toInt).sum,
         features.map(_(3).trim.toInt).sum)}.toList.sorted

println("LIST 1")
sumByTitle(listInput1).foreach(println)

println("LIST 2")
sumByTitle(listInput2).foreach(println)

您可以找到代码on Scastie供您使用。

作为旁注,您可能有兴趣将序列化和反序列化与业务逻辑分开。

Here you can find another Scastie notebook以相对天真的方式迈出了分离问题的第一步。

答案 1 :(得分:0)

parsename()

这样就可以保留元素的初始顺序。

答案 2 :(得分:0)

ListMap旨在保留插入Map的项目的顺序。

import collection.immutable.ListMap

def sumByTitle(listInput: List[String]): List[String] = {
  val itemPttrn = raw"(.*)(\d+),(\d+)\s*".r
  listInput.foldLeft(ListMap.empty[String, (Int,Int)].withDefaultValue((0,0))) {
    case (lm, str) =>
      val itemPttrn(k, a, b) = str  //unsafe
      val (x, y) = lm(k)
      lm.updated(k, (a.toInt + x, b.toInt + y))
  }.toList.map { case (k, (a, b)) => s"$k$a,$b" }
}

这有点不安全,因为如果输入字符串与正则表达式模式不匹配,它将抛出。

sumByTitle(listInput1)
//res0: List[String] = List(itemA,CATA,5,5, itemB,CATB,8,11)

sumByTitle(listInput2)
//res1: List[String] = List(itemA,CATA,2,4, itemB,CATB,4,5, itemC,CATC,1,2)

您会注意到尾随空格(如果有的话)不会被保留。