抱歉模糊描述,但我无法描述得更好。那么,问题 - 我有类的层次结构
sealed trait GameEvent
case object RoundStarted extends GameEvent
case object MessageSent extends GameEvent
....
解析游戏数据后,我有List [GameEvent]。根据业务逻辑,我需要提供在特定轮次“观看”游戏的能力。由RoundStartedEvent确定的每轮开始。 API方法有以下签名:
def load(id:Int, round:Int) = {
val game = repo.load(id)
val view = game.dropToRound(round)
view
}
case class Game(id:Int, events:List[GameEvent]){
def dropToRound(round:Int) = {
val newEvents = //events.filter() How? I need find index of "round"-th RoundStarted event and get all elements before it
this.copy(events = newEvents)
}
}
val testData = Game(1, List(RoundStarted//round 0, MessageSent, MessageSent, RoundStarted//round 1, MessageSent, RoundStarted//round 2))
//To retrieve all events before round 2 we calling load(1, 1)
assert(load(1, 1) shouldBe (Game(1,List(RoundStarted//round 0, MessageSent, MessageSent)))
我知道如何做到这一点,但是从功能上来说,更好的方法是什么?最好没有像scalaz这样的库,但如果真的很简洁 - 我也会接受它:)
答案 0 :(得分:2)
您实际上无法使用过滤器,因为您只想在特定情况发生之前收集事件。
此功能将收集事件:
def collectEvents(round: Int, events: List[GameEvent]): List[GameEvent] = {
def collectEventsList(r: Int, eventList: List[GameEvent], collectedEvents: List[GameEvent]): List[GameEvent] = {
eventList match {
case RoundStarted :: _ if r == 0 =>
collectedEvents
case RoundStarted :: y if r > 0 =>
collectEventsList(r - 1, y, RoundStarted :: collectedEvents)
case x :: y =>
collectEventsList(r, y, x :: collectedEvents)
case List() =>
collectedEvents
}
}
collectEventsList(round, events, List()).reverse
}
答案 1 :(得分:0)
这可能是两个世界中最糟糕的:它使用takeWhile
和可变var
。它几乎等同于命令式解决方案。但至少它很短:
case class Game(id: Int, events: List[GameEvent]) {
def dropToRound(round: Int): Game = {
var cnt = 0
val newEvents = events.takeWhile({
case RoundStarted => cnt += 1
cnt <= round
case _ => true
})
this.copy(events = newEvents)
}
}
<强>更新强>
以下是命令性代码的更纯粹的翻译:
case class Game(id: Int, events: List[GameEvent]) {
def dropToRound(round: Int): Game = {
val newEvents = events.foldLeft((List.empty[GameEvent], 0))((t, ev) => (t, ev) match {
case ((out, cnt), _) if cnt > round => t
case ((out, cnt), RoundStarted) if cnt == round => t
case ((out, cnt), RoundStarted) => (ev :: out, cnt + 1)
case ((out, cnt), _) => (ev :: out, cnt)
})._1.reverse
this.copy(events = newEvents)
}
}
明显的缺点是:
foldLeft
所以它无论如何都要经过整个事件列表reverse
。