2017-01-06 3 views
1

より「機能的」なスタイルでプログラミングするのは初めてです。通常は、一連のネストされたforeachループと+=を合計に書きます。Scalaでネストされたマップを使用してデータをロールアップする

私はのように見えるのデータ構造を有する:私が欲しいもの

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アプローチがここで有利です。

答えて

2
myMap.map(i => i._1 -> i._2.values.flatMap(_.toList).groupBy(_._1).map(i => i._1 -> i._2.map(_._2).sum)) 
  1. すべての値
  2. flatMapは、あなたができるcatsを使用して、すべてのグループ化された値との和
+0

ありがとう!私は最終的にあなたのソリューションを 'mapValues(_。values.flatten.groupBy(_._ 1).mapValues(_。map(_。_ 2).sum))'に変更しました。 – diplosaurus

1

を取得し、キー

  • によって
  • groupByをリストしてもらいます:

    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キーごとInt秒を合計した、(また、猫のライブラリが提供する、Monoid documentationを参照してください)Monoid[Map[String, Int]]インスタンスを使用して、毎年の勝利/損失マップを兼ね備えています。

  • +0

    「Int」の '1/*'より '0/+'をどうやって選ぶのですか?後者もモノイドです。 –

    +0

    @VictorMoroz Cats(とScalaz)のデフォルトの 'Monoid [Int]'は、 –

    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)) 
    
    1
    .mapValues { _.toSeq 
           .flatMap(_._2.toSeq) 
           .groupBy(_._1) 
           .mapValues(_.foldLeft(0)(_ + _._2)) } 
    
    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)) 
    
    関連する問題