Использование фьючерсов для расчета агрегатов по цепочке в Scala - PullRequest
0 голосов
/ 12 мая 2018

Привет, я новичок в scala. У меня есть образец, работающий над

import scala.concurrent.{Await, Future}

import scala.concurrent.ExecutionContext.Implicits.global

object Test {

  def main(args: Array[String]): Unit = {
    case class User(id: Int)
    case class Subject(id: Int, includeForTotal: Boolean)
    case class UserScore(userId: Int, score: Int)

    def getUsers(classID: Int): Future[Seq[User]] = {
      Future.successful(Seq(User(id = 1), User(id = 2)))
    }

    def getSubjects(userID: Int): Future[Seq[Subject]] = {
      Future.successful(Seq(Subject(id = 1, true), Subject(id = 2, false)))
    }

    def getScore(subjectID: Int, userId: Int): Future[Int] = {
      case class ScoreByUser(userId: Int, subjectID: Int, score: Int)
      val scoresStore = Seq(
        ScoreByUser(userId = 1, subjectID = 1, 60),
        ScoreByUser(userId = 1, subjectID = 2, 70),

        ScoreByUser(userId = 2, subjectID = 1, 75),
        ScoreByUser(userId = 2, subjectID = 2, 90))

      val score = scoresStore.find { x =>
        x.subjectID == subjectID && x.userId == userId
      }.map(_.score)

      Future.successful(score.getOrElse(0))
    }

    def getBonusScore(userId: Int): Future[Int] = {
       if (userId == 1) {
         Future.successful(30)
        }
       else {
        Future.successful(20)
       }
     }

    def getTotalScore(classID: Int): Future[Seq[UserScore]] = {
      // get users in class
      // for each user get subjects, filter subjects includeForTotal
     // sum scores for each user along with extra bonus score and return Future
    }

    import scala.concurrent.duration._
    val classId1Score = Await.result(getTotalScore(1), 5 seconds)
    println("class1: " + classId1Score)

    val classId2Score = Await.result(getTotalScore(1), 5 seconds)
    println("class2: " + classId2Score)

  }
}

Может ли кто-нибудь помочь мне найти getUsersTotalScoresFrom для каждого пользователя, которому дано class id для предмета, где includeForTotal истинно

1 Ответ

0 голосов
/ 12 мая 2018

вы можете сохранить flatMapping на будущее или использовать для понимания. Также ваша getScore функция неверна, так как score.getOrElse(0) вернет Any.

Пример,

import scala.concurrent.{Await, Future}

import scala.concurrent.ExecutionContext.Implicits.global

object Test {

  def main(args: Array[String]): Unit = {
    case class User(id: Int)
    case class Subject(id: Int, includeForTotal: Boolean)
    case class UserScore(userId: Int, score: Int)

    def getUsers(classID: Int): Future[Seq[User]] = {
      Future.successful(Seq(User(id = 1), User(id = 2)))
    }

    def getSubjects(userID: Int): Future[Seq[Subject]] = {
      Future.successful(Seq(Subject(id = 1, true), Subject(id = 2, false)))
    }

    def getScore(subjectID: Int, userId: Int): Future[Int] = {
      case class ScoreByUser(userId: Int, subjectID: Int, score: Int)
      val scoresStore = Seq(
        ScoreByUser(userId = 1, subjectID = 1, 60),
        ScoreByUser(userId = 1, subjectID = 2, 70),

        ScoreByUser(userId = 2, subjectID = 1, 75),
        ScoreByUser(userId = 2, subjectID = 2, 90))

      val score = scoresStore.find { x =>
        x.subjectID == subjectID && x.userId == userId
      }.map(_.score)

      Future.successful(score.getOrElse(0))
    }

    def getTotalScore(classID: Int): Future[Seq[UserScore]] = {

      getUsers(classID).flatMap { users =>
        Future.traverse(users) { user =>
          getSubjects(user.id).flatMap { userSubjects =>
            Future.traverse(userSubjects) { subject =>
              if (subject.includeForTotal) getScore(subject.id, user.id)
              else Future.successful(0)
            }
          }.map(_.sum).map(score => UserScore(user.id, score))
        }
      }
    }

    import scala.concurrent.duration._
    val classId1Score = Await.result(getTotalScore(1), 5 seconds)
    println("class1: " + classId1Score)

    val classId2Score = Await.result(getTotalScore(1), 5 seconds)
    println("class2: " + classId2Score)

  }
}

выход

class1: List(UserScore(1,60), UserScore(2,75))
class2: List(UserScore(1,60), UserScore(2,75))
...