groupby scala字符串列表

groupby scala字符串列表,scala,group-by,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", "

在计算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
它没有给我预期的结果,因为它改变了行的顺序


如何解决此问题?

如果您对排序感兴趣,只需返回
排序的
列表:

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)
您可以找到代码供您使用


作为补充说明,您可能对从业务逻辑中分离序列化和反序列化感兴趣

以一种相对幼稚的方法,迈出了分离关注点的第一步

def foldByTitle(listInput: List[String]): List[Item] =
  listInput.map(Item.parseItem).foldLeft(List.empty[Item])(sumByTitle)

val sumByTitle: (List[Item], Item) => List[Item] = (acc, curr) =>
  acc.find(_.name == curr.name).fold(curr :: acc) { i =>
    acc.filterNot(_.name == curr.name) :+ i.copy(num1 = i.num1 + curr.num1, num2 = i.num2 + curr.num2)
  }

case class Item(name: String, category: String, num1: Int, num2: Int)
object Item {
  def parseItem(serializedItem: String): Item = {
    val itemTokens = serializedItem.split(",").map(_.trim)
    Item(itemTokens.head, itemTokens(1), itemTokens(2).toInt, itemTokens(3).toInt)
  }
}

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

列表映射
旨在保留插入到
映射
的项目顺序

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)

您会注意到尾随空格(如果有)没有保留。

我的目的不是排序,我只想保持与输入中列表相同的顺序。据我所知,累积结果的顺序应该与原始列表中元素的顺序相似。这并不意味着原始列表中的元素是按字母顺序排序的。我是否有可能只用一个函数就可以做到这一点,这里不需要case cals hello所需输出中的所有空格都是错误的。我纠正了它。请你换一下房间好吗code@scalacode; 不需要更改代码。输入格式保留在输出中,除了任何尾随空格。这是否保证在列表中,我们将始终按排序顺序获得输入,如第一组A然后B?