在Scala中使用嵌套地图汇总数据

时间:2017-01-06 01:28:26

标签: scala functional-programming

在更多"功能性"中进行编程的新功能样式。通常我会写一系列嵌套的foreach循环和+=到总数。

我的数据结构如下:

Map(
  "team1" ->
    Map(
      "2015" -> Map("wins" -> 30, "losses" -> 5),
      "2016" -> Map("wins" -> 3, "losses" -> 7)
    ),
  "team2" ->
    Map(
      "2015" -> Map("wins" -> 22, "losses" -> 1),
      "2016" -> Map("wins" -> 17, "losses" -> 4)
    )
)

我想要的是一种数据结构,它简单地抛弃年份信息并由团队一起增加赢/输。

Map(
  "team1" -> Map("wins" -> 33, "losses" -> 12),
  "team2" -> Map("wins" -> 39, "losses" -> 5)
)

我一直在关注groupBy,但如果我没有这种嵌套结构,这似乎才有用。

有什么想法吗?或者更传统的势在必行/ foreach方法在这里是有利的。

5 个答案:

答案 0 :(得分:3)

myMap.map(i => i._1 -> i._2.values.flatMap(_.toList).groupBy(_._1).map(i => i._1 -> i._2.map(_._2).sum))
  
      
  1. 获取所有值
  2.   
  3. flatMap列出
  4.   
  5. groupBy按键
  6.   
  7. 获取所有分组值并求和
  8.   

答案 1 :(得分:2)

定义一个自定义方法,按键添加两个地图:

def addMap(x: Map[String, Int], y: Map[String, Int]) = 
    x ++ y.map{ case (k, v) => (k, v + x.getOrElse(k, 0))}


m.mapValues(_.values.reduce(addMap(_, _)))
// res16: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Int]] = 
// Map(team1 -> Map(wins -> 33, losses -> 12), team2 -> Map(wins -> 39, losses -> 5))

答案 2 :(得分:1)

使用cats即可:

#

import cats.implicits._ // or // import cats.instances.map._ // import cats.instances.int._ // import cats.syntax.foldable._ teams.mapValues(_.combineAll) // Map( // team1 -> Map(wins -> 33, losses -> 12), // team2 -> Map(wins -> 39, losses -> 5) // ) 使用combineAll实例(也由Cats库提供,请参阅Monoid documentation)结合每年的赢/输地图,其中Monoid[Map[String, Int]] s的总和对于每一把钥匙。

答案 3 :(得分:1)

.mapValues { _.toSeq
              .flatMap(_._2.toSeq)
              .groupBy(_._1)
              .mapValues(_.foldLeft(0)(_ + _._2)) }

答案 4 :(得分:0)

scala>   val sourceMap = Map(
     |     "team1" ->
     |       Map(
     |         "2015" -> Map("wins" -> 30, "losses" -> 5),
     |         "2016" -> Map("wins" -> 3, "losses" -> 7)
     |       ),
     |     "team2" ->
     |       Map(
     |         "2015" -> Map("wins" -> 22, "losses" -> 1),
     |         "2016" -> Map("wins" -> 17, "losses" -> 4)
     |       )
     |   )
sourceMap: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Int]]] = Map(team1 -> Map(2015 -> Map(wins -> 30, losses -> 5), 2016 -> Map(wins -> 3, losses -> 7)), team2 -> Map(2015 -> Map(wins -> 22, losses -> 1), 2016 -> Map(wins -> 17, losses -> 4)))

scala>   sourceMap.map { case (team, innerMap) =>
     |     val outcomeGroups = innerMap.values.flatten.groupBy(_._1)
     |     team -> outcomeGroups.map { case (outcome, xs) =>
     |       val scores = xs.map(_._2).sum
     |       outcome -> scores
     |     }
     |   }
res0: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Int]] = Map(team1 -> Map(losses -> 12, wins -> 33), team2 -> Map(losses -> 5, wins -> 39))