如何groupBy groupBy?

时间:2012-10-19 12:32:17

标签: scala group-by

我需要通过List[(A,B,C)]进行映射才能生成HTML报告。具体来说,一个

List[(Schedule,GameResult,Team)]

计划包含一个gameDate属性,我需要将其分组才能获得

Map[JodaTime, List(Schedule,GameResult,Team)]

我用它来显示gameDate表行标题。很容易:

val data = repo.games.findAllByDate(fooDate).groupBy(_._1.gameDate)

现在棘手的一点(对我而言)是,如何进一步细化分组以便能够成对地映射游戏结果?为了澄清,每个GameResult由一个团队的游戏“版本”(即分数,位置等)组成,与对手团队共享一个共同的Schedule gameID。

基本上,我需要在一行中显示游戏结果结果:

3 London Dragons vs. Paris Frogs 2

对gameDate进行分组让我做类似的事情:

data.map{case(date,games) =>
  // game date row headers
  <tr><td>{date.toString("MMMM dd, yyyy")}</td></tr>

  // print out game result data rows
  games.map{case(schedule,result, team)=>
    ...
    // BUT (result,team) slice is ungrouped, need grouped by Schedule gameID
  }
}

在旧版本的现有应用程序(PHP)中,我曾经

for($x = 0; $x < $this->gameCnt; $x = $x + 2) {...}

但是我更愿意引用变量名而不是后来的wtf-is-that-inducing:

games._._2(rowCnt).total games._._3(rowCnt).name games._._1(rowCnt).location games._._2(rowCnt+1).total games._._3(rowCnt+1).name

可能拉链或加倍(t1&lt; - data; t2&lt; - data)yield(?)或其他完全可以解决的问题。无论如何,有一个简洁的解决方案,现在就不要来找我......

2 个答案:

答案 0 :(得分:1)

也许我误解了你的要求,但在我看来,你所需要的只是一个额外的群体:

repo.games.findAllByDate(fooDate).groupBy(_._1.gameDate).mapValues(_.groupBy(_._1.gameID))

结果将是:

Map[JodaTime, Map[GameId, List[(Schedule,GameResult,Team)]]]

(其中GameIdSchedule.gameId

的返回类型

更新:如果您希望结果成对,那么模式匹配就是您的朋友,如Arjan所示。这会给我们:

val byDate = repo.games.findAllByDate(fooDate).groupBy(_._1.gameDate)
val data = byDate.mapValues(_.groupBy(_._1.gameID).mapValues{ case List((sa, ra, ta), (sb, rb, tb)) => (sa, (ta, ra), (tb, rb)))

这次的结果是:

Map[JodaTime, Iterable[ (Schedule,(Team,GameResult),(Team,GameResult))]]

请注意,如果没有2个条目具有相同的gameId,则会抛出MatchError。在实际代码中,您肯定想要检查这种情况。

答案 1 :(得分:1)

来自RégisJean-Gilles的灵魂:

val data = repo.games.findAllByDate(fooDate).groupBy(_._1.gameDate).mapValues(_.groupBy(_._1.gameID))

你说这不对,也许你只是没有以正确的方式使用它? 结果中的每个列表都是具有相同GameId的一对游戏。 你可以像这样制作html:

data.map{case(date,games) =>
  // game date row headers
  <tr><td>{date.toString("MMMM dd, yyyy")}</td></tr>

  // print out game result data rows
  games.map{case (gameId, List((schedule, result, team), (schedule, result, team))) =>
    ...
  }
}

由于你不需要gameId,你可以只返回配对的游戏:

val data = repo.games.findAllByDate(fooDate).groupBy(_._1.gameDate).mapValues(_.groupBy(_._1.gameID).values)

现在结果:

Map[JodaTime, Iterable[List[(Schedule,GameResult,Team)]]]

每个列表再次出现一对具有相同GameId的两场比赛