优雅的方式来验证斯卡拉地图

时间:2017-06-06 04:16:17

标签: scala apache-spark scala-collections

我的程序收到scala地图,要求是验证此地图(键值对)。例如:验证密钥值,将其值更改为可接受的格式等。在极少数情况下,我们也会在将映射传递给下层之前更新密钥。并不总是需要更新此映射,但仅当我们检测到有任何不受支持的键或值时才需要。但是,我们必须检查所有键/值对。我做了这样的事情:

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中为地图进行此验证?

由于

3 个答案:

答案 0 :(得分:3)

如果你把所有的模式放在彼此之上,那就更清楚了:

parameters.map{
  case (k@"checkPool", "1") => k -> "true"
  case (k@"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 (k@"checkPool", "1") => k -> "true"
  case (k@"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
)

答案 1 :(得分: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)
  })
}

您可以添加更多else if条件

答案 2 :(得分: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;我创建了一组测试来验证我的代码重构。

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