2014-10-29 82 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!") 
    } 
}