Scala 如何匹配一组可能的值?
我有一个集合,我想将另一个变量与其任何一个元素进行匹配。我知道我可以像这样手动执行此操作:Scala 如何匹配一组可能的值?,scala,Scala,我有一个集合,我想将另一个变量与其任何一个元素进行匹配。我知道我可以像这样手动执行此操作: fruits = Set("a", "b", "c", "d") toMatch = ("a", "fruit") toMatch match { case (("a" | "b" | "c" | "d", irrelevant)) => true } 但是有没有办法在match语句中使用水果,这样我就不必手动扩展它了 编辑:我目前正在使用if条件来实现这一点,我想知道是否有一些语法糖可以用
fruits = Set("a", "b", "c", "d")
toMatch = ("a", "fruit")
toMatch match {
case (("a" | "b" | "c" | "d", irrelevant)) => true
}
但是有没有办法在match语句中使用水果,这样我就不必手动扩展它了
编辑:我目前正在使用if条件来实现这一点,我想知道是否有一些语法糖可以用于内联操作
fruits = Set("a", "b", "c", "d")
toMatch = ("a", "fruit")
toMatch match {
case ((label, irrelevant)) if fruits.contains(label) => true
}
如果没有其他答案,我会将第一个回答“如果”的人标记为解决方案!很抱歉这里不够清晰
EDIT2:如果你想知道的话,原因是
fruits = Set("a", "b", "c", "d")
vegetables = Set("d", "e", "f")
toMatch = ("a", "fruit")
toMatch match {
case ((label, "fruit")) if fruits.contains(label) => true
case ((label, "vegetable")) if vegetables.contains(label) => true
}
我想将这两种情况结合起来,这样每个返回类型都有一个条件您可以使用match中的'if'语句来实现
val fruits = Set("a", "b", "c", "d")
val toMatch = ("a", "otherVar")
toMatch match {
case (fruit, _) if fruits.contains(fruit) => true
}
如果您只需要这两种情况,那么使用“If”或@Eugene answer就足够了,但对于更多情况,我会使用地图:
val fruits = Set("a", "b", "c", "d")
val vegetables = Set("d", "e", "f")
val meats = Set("q", "w")
val food = Map("fruits" -> fruits, "vegetables" -> vegetables, "meats" -> meats)
val toMatch = ("a", "fruit")
scala> food(toMatch._2)(toMatch._1)
res3: Boolean = true
您可以编写自定义提取器来获取所需的语法糖:
object FruitAndVegetable {
val fruits = Set("a", "b", "c", "d")
val vegetables = Set("d", "e", "f")
def main(args: Array[String]): Unit = {
List(
"a" -> "fruit",
"a" -> "vegetable",
"d" -> "fruit",
"d" -> "vegetable",
"e" -> "fruit",
"f" -> "vegetable"
) foreach {
toMatch =>
val result = toMatch match {
case CustomExtractor(`fruits`, "fruit") => "found a fruit"
case CustomExtractor(`vegetables`, "vegetable") => "veggy"
case _ => "Neither fruit nor veggy"
}
println(result)
}
}
object CustomExtractor {
def unapply(toMatch: (String, String)): Option[(Set[String], String)] =
if ((fruits contains toMatch._1) && toMatch._2 == "fruit") Some(fruits -> toMatch._2)
else if (vegetables contains toMatch._1) Some(vegetables -> toMatch._2)
else None
}
}
但是,请注意,这种方法有三个问题(可能更多,我想不出来):
依赖于CustomExtractor
和水果
集合,以及蔬菜
。原因:我们想从水果
中提取字符串
(因为我们匹配集合),所以我们需要找到一个包含该字符串的集合,即集合[String]
和水果
。由于这两个集合不明显,我们还需要知道在蔬菜
(此处:匹配的情况下返回哪个集合。两个集合中都包含_1
)。在这种情况下,我们需要查看“d”
toMatch.\u 2
仍然需要实现“unvency”匹配(尽管您可以比我做的更优雅)CustomExtractor
- 您的
-语句被对象标识符case
(或任何您想称之为它的东西)所“污染”CustomExtractor
PS:我对提取器不太熟悉,所以也许您可以想出一个更好的方法来使用提取器解决此问题 这里有另一个自定义的unapply方法,您可以使用它,它的类型更安全
object CustomExtractor {
case class Group(label: String, values: Set[String])
}
class CustomExtractor {
private[this] val labelMap = mutable.HashMap[String, CustomExtractor.Group]()
def newMatcher(label: String, values: String*): CustomExtractor.Group = {
if (labelMap.contains(label)) {
throw new IllegalArgumentException(s"Label Already Mapped: ${labelMap(label)}")
}
labelMap.getOrElseUpdate(label, new CustomExtractor.Group(label, Set(values: _*)))
}
def unapply(toMatch: (String, String)): Option[CustomExtractor.Group] = {
val (value, label) = toMatch
labelMap.get(label).filter(_.values.contains(value))
}
}
val extractor = new CustomExtractor
val fruits = extractor.newMatcher("fruit", "a", "b", "c", "d")
val vegetables = extractor.newMatcher("vegetable", "d", "e", "f")
val tests = List("a" -> "fruit", "a" -> "vegetable", "d" -> "fruit", "d" -> "vegetable", "e" -> "fruit", "f" -> "vegetable")
for (test <- tests) {
test match {
case extractor(`fruits`) => println(s"$test is definitely a fruit.")
case extractor(group) => println(s"$test was matched to ${group.label}.")
case _ => println(s"$test was not matched!")
}
}
对象自定义提取器{
案例类组(标签:String,值:Set[String])
}
类自定义提取器{
private[this]val labelMap=mutable.HashMap[String,CustomExtractor.Group]()
def newMatcher(标签:String,值:String*):CustomExtractor.Group={
if(标签映射包含(标签)){
抛出新的IllegalArgumentException(s“标签已映射:${labelMap(标签)}”)
}
labelMap.GetOrelsUpdate(标签,新CustomExtractor.Group(标签,集合(值:*))
}
def unapply(toMatch:(String,String)):选项[CustomExtractor.Group]={
val(值、标签)=t匹配
labelMap.get(label.filter)(u.values.contains(value))
}
}
val提取器=新的CustomExtractor
val fruits=提取器.newMatcher(“水果”、“a”、“b”、“c”、“d”)
val蔬菜=提取器.newMatcher(“蔬菜”、“d”、“e”、“f”)
val测试=列表(“a”->“水果”、“a”->“蔬菜”、“d”->“水果”、“d”->“蔬菜”、“e”->“水果”、“f”->“蔬菜”)
对于(test println(s“$test绝对是一个水果”)
案例提取器(组)=>println(s“$test与${group.label}匹配。”)
案例=>println(s“$test不匹配!”)
}
}
我目前使用if语句来做这件事,但我想知道是否有一些语法上的糖分来做这件事,你的意思是像水果.contains(“a”)
(或其他什么)?我目前使用一个if语句来做这件事,但我想知道是否有一些语法糖来做这件事!“if”语句正是它的语法糖水果(水果)
应该等同于水果。包含(水果)
问题的原因主要是这样做的,如果toMatch.\u 1匹配集合水果,并且不相关=“a”或toMatch._2与另一组蔬菜和蔬菜匹配“回答正确。对于if语句,我需要使用两个返回相同结果的案例。如果不存在更好的解决方案,我会将您的案例标记为解决方案。实际上,我不确定我是否理解了问题。如果提取独立于第二个元素,那么您可以将的返回类型unapply
更改为选项[Set][String]
并删除对toMatch.\u 2
的检查。显然,这使得第二个元组元素不相关,“a”->“蔬菜”
将与水果
以及“d”->“蔬菜”
和“a”->“甚至没有食物”
匹配。