2014-09-28 65 views
1

對不起,如果可以的話,請編輯它以更具描述性!這可以做得更漂亮嗎?匹配字符串到大小寫字段

有沒有辦法用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 
} 
+0

什麼是'res1'點?你可能想在res2中指定'res1.filter'? – 2014-09-28 17:13:35

+0

@EndeNeu你是對的,修正了 – Zavior 2014-09-28 17:22:12

+0

既然你想對同一個數據應用兩個過濾器,你可以先組合這兩個過濾器。因此,在第二場比賽中你不會有'res1',但是'res',這使得兩個代碼片段更加相似。我仍然不知道如何擺脫'.source'和'.category'的區別。我只是在想:「如果兩場比賽是相同的,你可以提取它們」 – 2014-09-28 17:39:00

回答

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 

    } 
+0

通過使匹配器函數具有通用性,可以使類型檢查更加準確。在你的例子中,似乎所有的值都是'String'類型。 – tuxdna 2014-09-28 20:15:41

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

用法

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 
} 
相關問題