这可以做得更漂亮吗?匹配字符串到案例类字段

时间:2014-09-28 17:10:36

标签: scala

对标题感到抱歉,如果可以的话,请将其编辑为更具描述性!

有没有办法用scala来概括这个?我有很多可以过滤的字段,这简直太丑了!我遇到的问题是将参数名称与案例类字段匹配,是否可以以更一般的方式完成,而不需要这么多的代码重复?

get("/MostClicked") { request =>
  val res = MongoDbOps.findMostClicked()
  val res1 = request.params.get("source") match {
    case None => res
    case Some(f) => res.filter(_.source == f)
  }
  val res2 = request.params.get("category") match {
    case None => res1
    case Some(f) => res1.filter(_.category == f)
  }
  // more of the same...

  render.plain {
    res2.toJson.prettyPrint
  }.toFuture
}

2 个答案:

答案 0 :(得分:3)

您可以尝试以下两种方法之一。

  case class MostClicked(
    source: String,
    category: String,
    rating: String)

  object MongoDbOps {
    def findMostClicked() = List[MostClicked]()
  }

  class Request {
    val params = Map[String, String]()
  }

  def get(path: String)(f: Request => String) = {
    f(new Request)
  }

首先使用匹配器列表,然后使用foldLeft依次应用它们:

  get("/MostClicked") { request =>
    val res = MongoDbOps.findMostClicked()

    val kfun = List(
      "source" -> ((x: MostClicked, y: String) => x.source == y),
      "category" -> ((x: MostClicked, y: String) => x.category == y),
      "rating" -> ((x: MostClicked, y: String) => x.rating == y))

    val r = kfun.foldLeft(res) { (x, y) =>
      request.params.get(y._1)
        .map(f => res.filter(y._2(_, f)))
        .getOrElse(x)
    }

    r.toString

    // more of the same...

    render.plain {
      r.toJson.prettyPrint
    }.toFuture

  }

或者只是让它更具可读性:

  get("/MostClicked") { request =>
    val res = MongoDbOps.findMostClicked()

    val res1 = request.params.get("source")
      .map(f => res.filter(_.source == f))
      .getOrElse(res)

    val res2 = request.params.get("category")
      .map(f => res.filter(_.category == f))
      .getOrElse(res1)

    val res3 = request.params.get("rating")
      .map(f => res.filter(_.rating == f))
      .getOrElse(res2)

    // more of the same...

    render.plain {
      res3.toJson.prettyPrint
    }.toFuture

  }

答案 1 :(得分:2)

我不得不将其分解为零件并计算出类型,因此采用较小的方法。 它可以在我的简单实验中工作,并尽可能地删除重复,但可能不那么可读?

请注意,除非您进行反思,否则仍需要创建参数的名称以及如何过滤它。

除了提高可读性和可维护性的类型之外,这看起来与tuxdna的答案相同

<强> SETUP

case class Request(params: Map[String, String])
case class Result(category: String, source: String)
type Filterer = (Result, String) => Boolean
case class FilterInfo(paramName: String, filterer: Filterer)
type Analyzer = FilterInfo => List[Result]
val request = Request(Map("source"->"b"))

提取方法

def reduce(filterInfos: List[FilterInfo], results: List[Result]) = {
  filterInfos.foldLeft(results) { (currentResult, filterInfo) =>
    request.params.get(filterInfo.paramName)
      .map(filterVal => currentResult.filter(filterInfo.filterer(_, filterVal)))
      .getOrElse(currentResult)
  }
}

<强> USAGE

val filterInfos = List(
              FilterInfo("source", (result, filterVal) => result.source == filterVal), 
              FilterInfo("category", (result, filterVal) => result.category == filterVal))
val res = List(Result("a","a"), Result("b", "b"))

reduce(filterInfos, res)

在您的示例中使用它更像是这样:

get("/MostClicked") { request =>
  val res = MongoDbOps.findMostClicked()
  val filterInfos = List(
              FilterInfo("source", (result, filterVal) => result.source == filterVal), 
              FilterInfo("category", (result, filterVal) => result.category == filterVal))  
  val finalResult = reduce(filterInfos, res)

  render.plain {
    finalResult.toJson.prettyPrint
  }.toFuture
}