Scala 有关某个状态的筛选器集合
很抱歉,描述不清楚,但我无法描述得更好。所以,问题是—— 我有等级制度Scala 有关某个状态的筛选器集合,scala,Scala,很抱歉,描述不清楚,但我无法描述得更好。所以,问题是—— 我有等级制度 sealed trait GameEvent case object RoundStarted extends GameEvent case object MessageSent extends GameEvent .... 解析完游戏数据后,我得到了列表[GameEvent]。根据业务逻辑,我需要提供在特定回合“查看”游戏的能力。每轮的开始时间由RoundStartedEvent确定。API方法具有以下签名: def l
sealed trait GameEvent
case object RoundStarted extends GameEvent
case object MessageSent extends GameEvent
....
解析完游戏数据后,我得到了列表[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这样的LIB,但如果它真的很简洁的话——我也接受:)您实际上不能使用过滤器,因为您只想在特定条件发生之前收集事件 此函数将收集以下事件:
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
}
这可能是两个世界中最糟糕的:它使用
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)
}
}
明显的缺点是:
反向
在
RoundStarted
类中使用对象而不编码相关的轮id的任何原因?我也考虑过递归。就我个人而言,我不认为它比命令式版本更优雅(更清晰),所以我对此表示怀疑。我会接受你的答案,如果有人不提供更优雅的解决方案:)是的,这几乎是我的初始代码)我只是感兴趣的是纯函数方法可以提供更好的东西。我曾考虑过State monad,但我的同事大多是scala新手,而且它的设计绝对过火,所以我真的很喜欢它doubt@AndreiMarkhel,我添加了另一个尝试,但它也并非没有自身的缺点。
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)
}
}