Scala替代一系列附加到列表的if语句?

时间:2017-10-20 08:31:11

标签: scala functional-programming

我在Scala中有Seq[String],如果Seq包含某些String,我会将相关消息附加到另一个列表中。

是否有更多'scalaesque'方法来实现这一点,而不是像我下面的列表中附加的一系列if语句?

val result = new ListBuffer[Err]()

val malformedParamNames = // A Seq[String]

if (malformedParamNames.contains("$top")) result += IntegerMustBePositive("$top")
if (malformedParamNames.contains("$skip")) result += IntegerMustBePositive("$skip")
if (malformedParamNames.contains("modifiedDate")) result += FormatInvalid("modifiedDate", "yyyy-MM-dd")
...

result.toList

4 个答案:

答案 0 :(得分:1)

如果你想使用一些scala iterables sugar我会用

sealed trait Err
case class IntegerMustBePositive(msg: String) extends Err
case class FormatInvalid(msg: String, format: String) extends Err

val malformedParamNames = Seq[String]("$top", "aa", "$skip", "ccc", "ddd", "modifiedDate")

val result = malformedParamNames.map { v =>
  v match {
    case "$top" => Some(IntegerMustBePositive("$top"))
    case "$skip" => Some(IntegerMustBePositive("$skip"))
    case "modifiedDate" => Some(FormatInvalid("modifiedDate", "yyyy-MM-dd"))
    case _ => None
  }
}.flatten


result.toList

如果你要求scala-esque的做事方式有很多可能,请注意。

使用flatmap

可以简化与flatten相结合的地图功能
sealed trait Err
case class IntegerMustBePositive(msg: String) extends Err
case class FormatInvalid(msg: String, format: String) extends Err

val malformedParamNames = Seq[String]("$top", "aa", "$skip", "ccc", "ddd", "modifiedDate")

val result = malformedParamNames.flatMap {
  case "$top" => Some(IntegerMustBePositive("$top"))
  case "$skip" => Some(IntegerMustBePositive("$skip"))
  case "modifiedDate" => Some(FormatInvalid("modifiedDate", "yyyy-MM-dd"))
  case _ => None
}


result

答案 1 :(得分:1)

大多数' scaleque'在保持可读性的同时我能想到的版本是:

  val map = scala.collection.immutable.ListMap(
    "$top" -> IntegerMustBePositive("$top"),
    "$skip" -> IntegerMustBePositive("$skip"),
    "modifiedDate" -> FormatInvalid("modifiedDate", "yyyy-MM-dd"))

 val result = for {
   (k,v) <- map
   if malformedParamNames contains k
 } yield v 

 //or 

 val result2 = map.filterKeys(malformedParamNames.contains).values.toList

答案 2 :(得分:0)

Benoit可能是最常用的方式,但是根据以后要阅读代码的人,您可能需要采用不同的方法。

// Some type definitions omitted
val malformations = Seq[(String, Err)](
  ("$top", IntegerMustBePositive("$top")),
  ("$skip", IntegerMustBePositive("$skip")),
  ("modifiedDate", FormatInvalid("modifiedDate", "yyyy-MM-dd")
)

如果您需要一个清单并且订单非常重要:

val result = (malformations.foldLeft(List.empty[Err]) { (acc, pair) =>
  if (malformedParamNames.contains(pair._1)) {
    pair._2 ++: acc // prepend to list for faster performance
  } else acc
}).reverse // and reverse since we were prepending

如果订单不重要(尽管订单不重要,您可能会考虑使用Set而不是List):

val result = (malformations.foldLeft(Set.empty[Err]) { (acc, pair) =>
  if (malformedParamNames.contains(pair._1)) {
    acc ++ pair._2
  } else acc
}).toList // omit the .toList if you're OK with just a Set

如果重复ifs中的谓词更复杂/更不均匀,那么可能需要更改畸形类型,就像响应更改时一样,但基本模式非常灵活。

答案 3 :(得分:0)

在此解决方案中,我们定义了一个映射列表,该映射列表成对使用您的IF条件和THEN语句,并迭代输入的列表并在匹配的地方应用更改。

//                     IF              THEN
case class Operation(matcher :String, action :String)

def processInput(input :List[String]) :List[String] = {

    val operations = List(
        Operation("$top", "integer must be positive"),
        Operation("$skip", "skip value"),
        Operation("$modify", "modify the date")
    )

    input.flatMap { in =>
        operations.find(_.matcher == in).map { _.action }
    }

}

println(processInput(List("$skip","$modify", "$skip")));

细分

operations.find(_.matcher == in)    // find an operation in our
                                    // list matching the input we are
                                    // checking. Returns Some or None

.map { _.action }                   // if some, replace input with action
                                    // if none, do nothing

input.flatMap { in =>               // inputs are processed, converted
                                    // to some(action) or none and the
                                    // flatten removes the some/none
                                    // returning just the strings.