是否可以使用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
答案 0 :(得分:16)
您可以将if
条件添加到匹配项中:
ls match {
case x if x.contains("foo") => // FOO
case x if x.contains("bar") => // BAR
case _ => // ELSE
}
然而,这不是最好的方式,因为每个if
检查都需要遍历列表,因此这不能很好地扩展。有各种不同的方法来处理这个问题,但我们需要更多地了解你的内涵,因为通常运行时语义会与你的代码不同(例如,你可以递归遍历列表寻找“foo”或“ bar“,但是假设你在列表中只有一个。”
答案 1 :(得分:8)
您可以使用类似
的功能实现此功能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
)
答案 2 :(得分:2)
正如弗兰克的回答所说,这是有可能的,但如果你这样做的话会很昂贵。
这取决于你想做什么。你想要返回“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
}
此代码未经过测试,但您明白了。
答案 3 :(得分:0)
如果你需要的是某种带有优先级的命令执行我可以建议
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
列表
答案 4 :(得分:0)
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")
在任何一种情况下,它只遍历列表一次。享受!