Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 有关某个状态的筛选器集合_Scala - Fatal编程技术网

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)
  }
}
明显的缺点是:

  • 你不能停止foldLeft,所以它会遍历整个事件列表
  • 附加的
    反向

  • 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)
      }
    }