Scala 使用另一个 Json 的键排序

Scala Sorting with Another Json's Key

我是 Scala 的新手,请帮助我。 我有 2 Json 个文件。我想用第二个 json.

中的键对第一个 json 进行排序

例如: 首先Json

{
    "id": 1,
    "response" : [{
            "user_id" : 1,
            "products" : [
                {
                    "product_id": 10,
                    "price": 200
                },
                {
                    "product_id": 13,
                    "price": 210
                },
                {
                    "product_id": 9,
                    "price": 320
                }
            ] 
        },{
            "user_id" : 2,
            "products" : [
                {
                    "product_id": 15,
                    "price": 200
                },
                {
                    "product_id": 13,
                    "price": 210
                },
                {
                    "product_id": 8,
                    "price": 320
                }
            ]
        }
    ]
}

还有我的第二个Json

{
    "sort": [
        {
            "user_id": 1,
            "products": [
                {
                    "id": 8,
                    "rank": 5
                },
                {
                    "id": 9,
                    "rank": 1
                },
                {
                    "id": 10,
                    "rank": 3
                },
                {
                    "id": 13,
                    "rank": 2
                },{
                    "id": 15,
                    "rank": 6
                },{
                    "id": 17,
                    "rank": 4
                },{
                    "id": 20,
                    "rank": 7
                },{
                    "id": 21,
                    "rank": 8
                },{
                    "id": 23,
                    "rank": 9
                }
            ]
        },{
            "user_id": 2,
            "products": [
                {
                    "id": 8,
                    "rank": 5
                },
                {
                    "id": 9,
                    "rank": 1
                },
                {
                    "id": 10,
                    "rank": 3
                },
                {
                    "id": 13,
                    "rank": 2
                },{
                    "id": 15,
                    "rank": 6
                },{
                    "id": 17,
                    "rank": 4
                },{
                    "id": 20,
                    "rank": 7
                },{
                    "id": 21,
                    "rank": 8
                },{
                    "id": 23,
                    "rank": 9
                }
            ]
        }
    ]
}

我想根据第二 Json 的排名对第一 json 进行排序。

输出应该像每个用户应该根据在第二个 JSON.

上为每个用户指定的排名对其产品进行排序

这是目前为止我尝试过的方法

def sortedRes() = Action.async {
    val url = //1st json url
    val sortUrl = //2nd json url
    ws.url(url).get().map { response =>
      val value: JsValue = Json.parse(response.body)
      val result: Either[Exception, SampleResponses] = value.validate[SampleResponses] match {
        case JsSuccess(searchResponse, _) =>
          Right(searchResponse)
        case JsError(errors) =>
          Left(new Exception("Couldn't parse Search API response"))
      }

      val values: List[SampleResponse] = result.right.get.responses

      ws.url(sortUrl).get().map { response =>
        val sorted: JsValue = Json.parse(response.body)


        val sortRespResult: Either[Exception, Sort] = sorted.validate[Sort] match {
          case JsSuccess(sortResponse, _) =>
            Right(sortResponse)
          case JsError(errors) =>
            Left(new Exception("Couldn't parse because of these errors : " + errors))
        }

        val prodRankDetails: List[SampleRank] = sortRespResult.right.get.sort

        println("prod = " + prodRankDetails.head.products.sortWith(_.rank > _.rank))
      }
      Ok(Json.toJson(result.right.get))
    }
  }

在最后一个打印语句中,我对第二个 json 的第一个用户产品进行了排序。我想要得到的是我的第一个 json 根据第二个用户排序。

这是我的模型class

package models

import play.api.libs.functional.syntax._
import play.api.libs.json.Reads._
import play.api.libs.json._ // Combinator syntax


object sample {
  case class SampleProduct(productId:Int, price: Int)
  case class SampleResponse(userId: Int, products: List[SampleProduct])
  case class SampleResponses(id: Int, responses: List[SampleResponse])
  case class SampleRankedProduct(id: Int, rank: Int)
  case class SampleRank(userId: Int, products: List[SampleRankedProduct])
  case class Sort(sort: List[SampleRank])

  implicit val productReads: Reads[SampleProduct] = (
    (JsPath \ "product_id").read[Int] and
      (JsPath \ "price").read[Int]
    )(SampleProduct.apply _)

  implicit val productWrites: Writes[SampleProduct] = (
    (JsPath \ "product_id").write[Int] and
      (JsPath \ "price ").write[Int]
    )(unlift(SampleProduct.unapply))

  implicit val responseReads: Reads[SampleResponse] = (
    (JsPath \ "user_id").read[Int] and
      (JsPath \ "products").read[List[SampleProduct]]
    )(SampleResponse.apply _)

  implicit val responseWrites: Writes[SampleResponse] = (
    (JsPath \ "user_id").write[Int] and
      (JsPath \ "products").write[List[SampleProduct]]
    )(unlift(SampleResponse.unapply))

  implicit val responsesReads: Reads[SampleResponses] = (
    (JsPath \ "id").read[Int] and
      (JsPath \ "response").read[List[SampleResponse]]
    )(SampleResponses.apply _)

  implicit val responsesWrites: Writes[SampleResponses] = (
    (JsPath \ "id").write[Int] and
      (JsPath \ "response").write[List[SampleResponse]]
    )(unlift(SampleResponses.unapply))

  implicit val rankedProductReads: Reads[SampleRankedProduct] = (
    (JsPath \ "id").read[Int] and
      (JsPath \ "rank").read[Int]
    )(SampleRankedProduct.apply _)

  implicit val rankedProductWrites: Writes[SampleRankedProduct] = (
    (JsPath \ "id").write[Int] and
      (JsPath \ "rank ").write[Int]
    )(unlift(SampleRankedProduct.unapply))

  implicit val rankReads: Reads[SampleRank] = (
    (JsPath \ "user_id").read[Int] and
      (JsPath \ "products").read[List[SampleRankedProduct]]
    )(SampleRank.apply _)

  implicit val rankWrites: Writes[SampleRank] = (
    (JsPath \ "user_id").write[Int] and
      (JsPath \ "products").write[List[SampleRankedProduct]]
    )(unlift(SampleRank.unapply))

  implicit val sortReads: Reads[Sort] = (JsPath \ "sort").read[List[SampleRank]].map(x ⇒ Sort(x))

  implicit val sortWrites: Writes[Sort] = (__ \ "sort").write[List[SampleRank]].contramap { (person: Sort) => person.sort }
}

使用第二个的排名对第一个 JSON 进行排序的方法是这样的:

....
val prodRankDetails: List[SampleRank] = sortRespResult.right.get.sort

val sortedResults = values.copy(
  responses = values.responses.map { resultForUser =>
    val rankingForUser = prodRankDetails
      .find(_.userId == resultForUser.userId)
      .getOrElse(throw new RuntimeException(s"Rank not found for user ${resultForUser.userId}"))
      .products
      .map(product => (product.id, product.rank))
      .toMap

    resultForUser.copy(
      products = resultForUser.products.sortWith((a, b) =>
        rankingForUser.getOrElse(a.productId, Int.MaxValue) < rankingForUser.getOrElse(b.productId, Int.MaxValue))
    )

  }
)
Ok(Json.toJson(sortedResults))

应该在你得到 prodRankDetails 之后立即执行。而且当您管理 Future 时,响应将在 .map 内可用。 因此,您还必须将该地图内部的 Ok(...) 移动到外部 Future.

flatMap

希望对您有所帮助。