是否可以使用 Scala 模式匹配重写以下代码?
val ls: List[String] = ??? // some list of strings
val res = if (ls.contains("foo")) FOO
else if (ls.contains("bar")) BAR
else SOMETHING_ELSE
是否可以使用 Scala 模式匹配重写以下代码?
val ls: List[String] = ??? // some list of strings
val res = if (ls.contains("foo")) FOO
else if (ls.contains("bar")) BAR
else SOMETHING_ELSE
您可以if
向匹配项添加条件,如下所示:
ls match {
case x if x.contains("foo") => // FOO
case x if x.contains("bar") => // BAR
case _ => // ELSE
}
但是,这不是最好的方法,因为每个if
检查都需要遍历列表,所以这不能很好地扩展。有多种不同的方法来处理这个问题,但我们需要更多地了解您的意图,因为通常运行时语义会与您的代码不同(例如,您可以递归遍历列表以查找“foo”或“ bar”,但这会假设您在列表中只有一个)。
您可以使用类似的函数来实现它
def onContains[T](xs: Seq[String], actionMappings: (String, T)*): Option[T] = {
actionMappings collectFirst {
case (str, v) if xs contains str => v
}
}
并像这样使用它:
val x = onContains(items,
"foo" -> FOO,
"bar" -> BAR
)
正如弗兰克的回答所说,如果你以肮脏的方式去做,这是可能的,但代价高昂。
这取决于你想做什么。你想返回那个“foo”或“bar”的索引(例如)吗?然后你会做这样的事情:
def indexOf[T]: (List[T], T) => Int = (ls, x) => ls match {
case Nil => -1
case e::es if( e.equals(x) ) => 0
case e::es => val i = indexOf( es, x ); if( i < 0 ) i else i + 1
}
此代码未经测试,但您明白了。
如果您需要的是某种带有优先级的命令执行,我可以建议
def executeCommand(input: List[String]): Option[Unit] = {
val priorities = Map(
"foo" -> 1,
"bar" -> 2,
"baz" -> 3) withDefault(_ => 4)
def extractCommand(cmds: List[String]): Option[String] =
(cmds sortBy priorities).headOption
extractCommand(input) map {
case "foo" => println("found foo")
case "bar" => println("found bar")
case "baz" => println("found baz")
case _ => println("no known command")
}
}
在这个特定的实现中,没有返回有意义的结果(你只考虑副作用),但如果你的案例应该返回一些值,你会发现它被包裹在一个Option
方法结果中。
根据
您的附加评论更新
def execute(input: List[String]): Option[String] = {
val commands: PartialFunction[String, String] = {
case "foo" => "result for foo"
case "bar" => "result for bar"
case "baz" => "result for baz"
}
(input find commands.isDefinedAt) map commands
}
这仅适用于您的命令是独占的,只有一个应该在input
列表中
val ls = List[String]("bar", "foo", "baz") // stuff to check against
val mappy = Map[String, String]("foo" -> "FOO", "bar" -> "BAR") // conversions go here
val res = ls.flatMap{
case x: String => mappy.get(x)
} match {
case Seq(y) => y
case Nil => "SOMETHING_ELSE" // the `else` case goes here
case _ => new Exception("could be more than one thing") // handle this however you want
}
我相信这是最 Scalaesque 的方式。案例及其结果之间的关系简明扼要地在 中进行了说明Map
,您可以选择根据需要处理多个结果。你确实说过
列表很短(最多 4 或 5 个项目),并且只能包含其中一个搜索值
但有些人可能需要处理这种可能性。如果你真的,真的不关心多个匹配,你可以做
val res = ls.flatMap(mappy.get).headOption.getOrElse("SOMETHING_ELSE")
在任何一种情况下,它都只遍历列表一次。享受!