使用另一个Json密钥进行Scala排序

时间:2018-01-23 06:51:57

标签: json scala playframework-2.0

我是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基于第二个用户排序。

这是我的模型类

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

1 个答案:

答案 0 :(得分:5)

使用第二个JSON排名来排序第一个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之后执行。当您管理.map时,响应也会在Future内提供。 因此,您还必须移动该地图内的Ok(...)并移至外部flatMap Future

希望这有帮助。