2017-06-06 67 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更好看;我创建了一组测试来验证我的代码重构。

我希望你会发现我的帮助。