2017-06-06 31 views
1

我的程序收到一個斯卡拉地圖,要求是驗證這個地圖(鍵值對)。例如:驗證鍵值,將其值更改爲可接受的格式等。在極少數情況下,我們還會在將地圖傳遞到向下層之前更新密鑰。並不總是需要更新此映射,但只有當我們檢測到有任何不支持的鍵或值時。但是,我們必須檢查所有鍵/值對。我在做一些事情是這樣的:優雅的方式來驗證斯卡拉地圖

private def updateMap (parameters: Map[String, String]): Map[String, String] = { 

parameters.map{ 

    case(k,v) => k match { case "checkPool" => 


    (k, (if (k.contains("checkPool")) 
     v match { 
     case "1" => "true" 
     case _ => "false" 
     } 
    else v)) 

    case "Newheader" => (k.replace("Newheader","header"),v) 
    case _ =>(k,v) 
    } 


    case _ => ("","") 
} 

} 

像這樣做驗證和轉換鍵/值,以支持那些代碼的增加。是否有更簡潔的方式在Scala中進行地圖驗證?

感謝

+0

關鍵值是否等於「NewHeader」和「checkPool」,還是它們是較長字符串的一部分(使用contains函數)?如果他們是關鍵字符串的一部分,那麼Ramesh Maharjan的解決方案很好,否則存在一種更清晰的方式。 – Shaido

回答

0

簡單if else條件匹配似乎是最好的選擇。

def updateMap(parameters: Map[String, String]): Map[String, String] = { 
    parameters.map(kv => { 
    var key = kv._1 
    var value = kv._2 
    if(key.contains("checkPool")){ 
     value = if(value.equals("1")) "true" else "false" 
    } 
    else if(key.contains("Newheader")){ 
     key = key.replace("Newheader", "header") 
    } 
    (key, value) 
    }) 
} 

您可以添加更多elseif條件

3

,如果你把一個在另一個之上所有的模式它會更清楚:

parameters.map{ 
    case ([email protected]"checkPool", "1") => k -> "true" 
    case ([email protected]"checkPool", _") => k -> "false" 
    case ("Newheader", v) => "header" -> v 
    // put here all your other cases 
    case (k, v) => k -> v //last possible case, if nothing other matches 
} 

爲清楚起見,你也可以把不同的驗證在局部功能:

type Validator = PartialFunction[(String, String), (String, String) 
val checkPool: Validator = { 
    case ([email protected]"checkPool", "1") => k -> "true" 
    case ([email protected]"checkPool", _") => k -> "false" 
} 
val headers: Validator = { 
    case ("Newheader", v) => "header" -> v 
} 

然後把你所有的驗證一前一後在map

parameters.map(
    checkPool orElse 
    headers orElse 
    ... orElse 
    PartialFunction(identity[(String, String)]) //this is the same as case (k, v) => k -> v 
) 
0

如果我理解正確的話,你的目標是減少代碼修補程序應用到地圖所需的時間。

如另一個答案中提出的想法是在定義更新規則和應用它們之間進行拆分,以便在需要新更新時只需增加第二個更新規則,而不必重新定義如何應用規則。

我們可以將規則的定義建模爲一個映射,從一個鍵到一個定義轉換的函數。轉換本身可以在簡單函數之上進行建模。

然後可以將應用規則定義爲應用這些函數並將它們應用於已定義的鍵。

sealed trait Patch extends (((String, String)) => (String, String)) 

final class PatchValue(update: String => String) extends Patch { 
    override def apply(pair: (String, String)): (String, String) = pair.copy(_2 = update(pair._2)) 
} 

final class PatchKey(update: String => String) extends Patch { 
    override def apply(pair: (String, String)): (String, String) = pair.copy(_1 = update(pair._1)) 
} 

final class MalleableMapPatching(rules: Map[String, Patch]) { 

    def updatePair(pair: (String, String)): (String, String) = { 
    rules.filterKeys(_ == pair._1).foldLeft(pair) { 
     case (pair, (_, patch)) => 
     patch(pair) 
    } 
    } 

    def update(parameters: Map[String, String]): Map[String, String] = 
    parameters.map(updatePair) 

} 

既然已經完成了規則定義部分,我們就可以創建一個具有一組準備好的規則的具體對象。

val patchingRules = 
    Map(
    "checkPool" -> new PatchValue(value => if (value == "1") "true" else "false"), 
    "Newheader" -> new PatchKey(_ => "header") 
) 

val patcher = new MalleableMapPatching(patchingRules) 

如果您有興趣參加在我的解決方案,here is the code on Github更好看;我創建了一組測試來驗證我的代碼重構。

我希望你會發現我的幫助。