验证scala映射的优雅方法

验证scala映射的优雅方法,scala,apache-spark,scala-collections,Scala,Apache Spark,Scala Collections,我的程序收到一个scala映射,要求验证这个映射(键值对)。例如:验证键值,将其值更改为可接受的格式等。在极少数情况下,我们会在将贴图传递到下层之前更新键值。并不总是需要更新此映射,但仅当我们检测到存在任何不受支持的键或值时才需要更新。但是,我们必须检查所有键/值对。我在做这样的事情: private def updateMap ( parameters: Map[String, String]): Map[String, String] = { parameters.map{ case

我的程序收到一个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中是否有一种更干净的方法来验证地图


谢谢

简单的
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)
  })
}

如果条件

您可以添加更多的
其他
,如果您将所有模式置于彼此之上,则会更加清晰:

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
}
然后将所有验证器一个接一个地放在
地图中

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

如果我理解正确,您的目标是减少向地图应用修补程序所需的代码量

正如在另一个答案中所建议的那样,这个想法将在定义更新规则和应用它们之间进行划分,这样您就可以在需要新的更新时增加第二个规则,而不必重新定义如何应用规则

我们可以将规则的定义建模为从键到定义转换的函数的映射。转换本身可以在简单函数的基础上建模

然后,可以将应用规则定义为应用这些函数,并将这些函数应用于已定义的键

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)
如果您有兴趣更好地了解我的解决方案;我创建了一组测试来验证我对代码的重构

我希望您会觉得我的take很有帮助。

是等于“NewHeader”和“checkPool”的键值,还是它们是较长字符串的一部分(您使用的是contains函数)?如果它们是关键字符串的一部分,那么Ramesh Maharjan的solotion是好的,否则存在更干净的方法。