可以说我有一组这样的类Action
:actions: Set[Action]
,每个Action
类都有一个val consequences : Set[Consequence]
,其中Consequence
是一个case类。
我希望获得一张地图Consequence
,Set[Action]
以确定导致特定行为的动作Consequence
。显然,由于一个Action
可以有多个,Consequence
它可以出现在地图的多个集合中。
我一直在努力解决这个问题(我是Scala的新手),想知道是否可以使用诸如map()和groupBy()之类的方法来做到这一点,但是有点失落。我不希望恢复命令式编程,尤其是当有一些Scala映射功能可以提供帮助时。
实现此目标的最佳方法是什么?
不太优雅,因为groupBy
无法处理已经在上进行操作的情况Tuple2
,因此您最终需要进行许多麻烦和麻烦:
case class Conseq()
case class Action(conseqs: Set[Conseq])
def gimme(actions: Seq[Action]): Map[Conseq, Set[Action]] =
actions.flatMap(a => a.conseqs.map(_ -> a))
.groupBy(_._1)
.mapValues(_.map(_._2)(collection.breakOut))
第一行将每个动作及其所有结果“压缩”在一起,产生a Seq[(Conseq, Action)]
,并将其与第一个product元素给定在一起分组Map[Conseq, Seq[(Conseq, Action)]
。因此,最后一步需要将地图的值从Seq[(Conseq, Action)]
转换为Set[Action]
。可以使用来完成mapValues
。如果没有显式的生成器工厂,它将产生a Seq[Action]
,因此必须写.mapValues(_.map(_._2)).toSet
。传入collection.breakOut
第二个参数列表map
可以节省一个步骤并map
直接生成Set
集合类型。
另一种可能性是使用嵌套折叠:
def gimme2(actions: Seq[Action]) = (Map.empty[Conseq, Set[Action]] /: actions) {
(m, a) => (m /: a.conseqs) {
(m1, c) => m1.updated(c, m1.getOrElse(c, Set.empty) + a)
}
}
这也许更具可读性。我们从一个空的结果图开始,遍历这些动作,然后在内部折叠中遍历每个动作的结果,这些结果被合并到结果图中。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句