Как и предполагал другой ответ, вы должны использовать библиотеку play-json. Он действительно мощный и имеет множество функций, включая сопоставление объектов, анализ и обработку ошибок.
import play.api.libs.json._
import play.api.data.validation.ValidationError
case class User(id: String, paid: Boolean)
object User {
implicit val format: OFormat[User] = Json.format[User]
}
case class UserCourseStat(rating: Int, completed: Boolean, user: User)
object UserCourseStat {
implicit val format: OFormat[UserCourseStat] = Json.format[UserCourseStat]
}
case class Data(technology: String, title: String, users: List[UserCourseStat])
object Data {
implicit val format: OFormat[Data] = Json.format[Data]
}
val jsString = """[{"technology":"C","users":[{"rating":5,"completed":false,"user":{"id":11111,"paid":true}},{"rating":4,"completed":false,"user":{"id":22222,"paid":false}}],"title":"CS50"},{"technology":"C++","users":[{"rating":3,"completed":true,"user":{"id":33333,"paid":false}},{"rating":5,"completed":true,"user":{"id":44444,"paid":false}}],"title":"Introduction to C++"},{"technology":"Haskell","users":[{"rating":5,"completed":false,"user":{"id":55555,"paid":false}},{"rating":null,"completed":true,"user":{"id":66666,"paid":false}}],"title":"Course on Haskell"}]"""
val rowData: JsValue = Json.parse(jsString)
rowData.validate[List[Data]] match {
case JsSuccess(dataList: List[Data], _) =>
val chosenTitles = List("Course on Haskell", "Introduction to C++", "CS50")
//map of each chosen title to sequence of it's users
val chosenTitleToUsersMap = chosenTitles.map { title =>
title -> dataList.filter(_.title == title)
.flatMap(_.users.map(_.user))
.toSet
}.toMap
//map of each chosen title to sequence of it's paid users
val chosenTitleToPaidUsersMap = chosenTitleToUsersMap.map { case (title, users) =>
title -> users.filter(_.paid)
}
//Calculate users who have completed each of the chosen title
val allUsers = dataList.flatMap(_.users.map(_.user)).toSet
val usersWhoCompletedAllChosenTitles = allUsers.filter{ user =>
chosenTitles.forall { title =>
chosenTitleToUsersMap.get(title).flatten.contains(user)
}
}
case JsError(errors: Seq[(JsPath, Seq[ValidationError])]) =>
//handle the error case
???
}
Относительно 3 вопросов, которые у вас были:
- Это хороший подход для получения списка из 3 названий?
Я вижу там две небезопасные операции, такие как InstanceOf и e ("title"), последняя из-за того, что метод Map не используется .get (key), он выдаст исключение, если ключ не найден.
- Как получить Список, содержащий количество платных пользователей для каждого из трех последних названий?
Оценивается выше в val с именем "selectedTitleToPaidUsersMap"
- Как получить список, содержащий количество пользователей, прошедших курс по каждому из трех последних названий?
Оценивается выше в val с именем "usersWhoCompletedAllChosenTitles"