2014-10-29 80 views
1

我有一个集合,我想匹配任何一个元素的另一个变量。我知道我可以手动执行此操作是这样的:如何匹配一组可能的值?

fruits = Set("a", "b", "c", "d") 
toMatch = ("a", "fruit") 
toMatch match { 
    case (("a" | "b" | "c" | "d", irrelevant)) => true 
} 

但是,有没有办法在比赛语句中使用的水果,所以我不必手动展开

编辑:我目前使用一个如果要做这种情况下,我想知道是否有一些语法糖,我可以用来做内联

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 
} 

我想这两种情况结合起来,所以我有一个条件每个返回类型

+0

我目前使用的if语句这样做,但不知道是否有一些语法糖要做到这一点 – Nicomoto 2014-10-29 21:48:40

+0

你的意思是像'fruits.contains(“A”)'(或其他)? – 2014-10-29 21:50:47

回答

1

你可以做到这一点“,如果“声明匹配

val fruits = Set("a", "b", "c", "d") 
    val toMatch = ("a", "otherVar") 

    toMatch match { 
    case (fruit, _) if fruits.contains(fruit) => true 
    } 
+0

我目前使用if语句来做到这一点,但想知道是否有一些语法糖来做到这一点! – Nicomoto 2014-10-29 21:49:11

+0

'if'语句完全是句法糖 – 2014-10-29 21:49:57

+0

'fruits(fruit)'应该相当于'fruits.contains(水果)' – 2014-10-29 21:53:21

1

如果你只需要这两种情况,然后使用‘如果’或@Eugene答案是足够了,但更多的情况下,我会使用地图:

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 
1

你可以写一个自定义的提取来得到你想要这个语法糖:

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具有相关性的fruitsvegetables收集,藏汉为"fruit"。原因:我们想从String中提取Set[String](因为我们与该集合相匹配),所以我们需要找到一个包含字符串的集合,即fruitsvegetables。由于集合并不明确,因此我们还需要知道哪些集合返回,以防两个集合中包含toMatch._1(这里是:"d")。在这种情况下,我们需要看看toMatch._2

  • CustomExtractor仍需落实“unfancy”匹配(但你可以做到这一点更优雅比我做了什么)

  • case -statements获得“污染”的对象标识符CustomExtractor(或任何你想要的打电话)

我只会考虑这个解决方案,如果你有很多match -statements匹配这些值。在这种情况下,你只需要写一次提取器就可以重新使用它。

PS:我对萃取器不是很熟悉,所以也许你可以想出一个更好的方法来使用萃取器来解决这个问题。

+0

其实,我不确定我是否确实掌握了这个问题。如果在第二个元素**上提取**是独立的,那么你可以将''unapply''的返回类型改为''Option [Set [String]]''并且移除''toMatch._2'上的检查'。很显然,这使得第二个元组元素无关紧要,并且''a“ - >”vegetable“'将与'fruit'以及'”d“ - >”vegetable“'和'”a“ - >”不匹配食品“'。 – 2014-10-30 00:46:15

0

这是另一种可以使用的自定义非应用方法,它有点更安全。

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!") 
    } 
}