在(Skey)的Seq上Scala groupby键总和值保持顺序

时间:2019-04-25 08:08:29

标签: scala collections

我正在尝试解决对scala元组进行分组和求和并保持键顺序的问题。

val arrayTuples = Array((A, 38) , (B, 150), (B, 250), (B, 890), (D, 600), (C, 515))

Map(A -> 38, B -> 1290, D -> 600, C -> 515)

正在做

val aMap = arrayTuples .groupBy(_._1)

似乎弄乱了顺序。帮助表示赞赏。

编辑:保持首次遇到的顺序。

3 个答案:

答案 0 :(得分:5)

您可以使用#h1-container h1 { /*Your rules*/ } 来保留顺序,但是如果您希望按照注释中的说明从左至右进行排序,则需要一些额外的步骤。

ListMap

由于//note the new order of elements val arrayTuples = Array(('A', 38), ('B', 150), ('D', 600), ('B', 250), ('C', 515), ('B', 890)) import collection.immutable.ListMap arrayTuples.foldRight(ListMap[Char,Int]()) { case ((c,n), lm) => lm.updated(c , lm.getOrElse(c, 0)+n) }.foldRight(ListMap[Char,Int]()){case (elem,lm) => lm+elem} //res0: ListMap[Char,Int] = ListMap(A -> 38, B -> 1290, D -> 600, C -> 515) 保留了最后一个顺序,在这种情况下会将ListMap项移到末尾,所以我决定移至B,这将{{1} }输入到末尾,然后再次foldRight来颠倒整个过程。

答案 1 :(得分:3)

您可以像这样获得插入顺序图:

import scala.collection.immutable.ListMap

val tuples = List(("A", 38) , ("B", 150), ("B", 250), ("B", 890), ("C", 515), ("D", 600))

val initMap = ListMap.empty[String, List[(String, Int)]].withDefaultValue(List.empty)

val aMap = tuples.foldLeft(initMap) { case (acc, (k, v)) =>
  val newList = (k -> v) :: acc(k)
  acc + (k -> newList)
}

println(aMap) // Map(A -> List((A,38)), B -> List((B,890), (B,250), (B,150)), C -> List((C,515)), D -> List((D,600)))

答案 2 :(得分:2)

默认情况下,scala Map是未排序的集合,但是您可以使用ListMap

val summedTuples = arrayTuples
  .groupBy(_._1)
  .mapValues(_.map(_._2).sum)
  .toSeq.sortBy(_._1)
// ArrayBuffer((A,38), (B,1290), (C,515), (D,600))

ListMap(summedTuples: _*)
// Map(A -> 38, B -> 1290, C -> 515, D -> 600)

编辑:因此,在重新阅读问题以及有关“首次遇到的”排序的说明后,我不再只是删除我的答案,而是在下面稍加修改。我仍然更喜欢上面接受的答案,但是选择其他方法也不会受伤:

import scala.collection.immutable.ListMap

val arrayTuples = Array(("A", 38) , ("B", 150), ("B", 250), ("B", 890), ("D", 600), ("C", 515))

val summedTuples = arrayTuples
  .groupBy(_._1)
  .mapValues(_.map(_._2).sum)
  .toSeq.sortBy(k => arrayTuples.indexWhere(_._1 == k._1)) // yes, I'm sorting by the original order...

ListMap(summedTuples : _*) // Map(A -> 38, B -> 1290, D -> 600, C -> 515)