Scala 中的模式匹配元组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12500454/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pattern Matching tuples in Scala
提问by aerotwelve
Trying to get a handle on pattern matching here-- coming from a C++/Java background it's very foreign to me.
试图在这里处理模式匹配——来自 C++/Java 背景对我来说非常陌生。
The point of this branch is to check each member of a List dof tuples [format of (string,object). I want to define three cases.
此分支的重点是检查d元组列表[(string,object) 的格式] 的每个成员。我想定义三种情况。
1) If the counter in this function is larger than the size of the list (defined in another called acc), I want to return nothing (because there is no match)
2) If the keygiven in the input matches a tuple in the list, I want to return its value (or, whatever is stored in the tuple._2).
3) If there is no match, and there is still more list to iterate, increment and continue.
1) 如果此函数中的计数器大于列表的大小(在另一个称为 acc 中定义),我不想返回任何内容(因为没有匹配) 2)如果key输入中的给定与列表中的元组匹配,我想返回它的值(或者,任何存储在 tuple._2 中的值)。3) 如果没有匹配,还有更多的列表要迭代,递增并继续。
My code is below:
我的代码如下:
def get(key:String):Option[Any] = {
var counter: Int = 0
val flag: Boolean = false
x match {
case (counter > acc) => None
case ((d(counter)._1) == key) => d(counter)._2
case _ => counter += 1
}
My issue here is while the first case seems to compile correctly, the second throws an error:
我的问题是,虽然第一种情况似乎可以正确编译,但第二种情况会引发错误:
:36: error: ')' expected but '.' found.
case ((d(counter)._1) == key) => d(counter)._2
The third as well:
第三个也是:
scala> case _ => counter += 1 :1: error: illegal start of definition
But I assume it's because the second isn't correct. My first thought is that I'm not comparing tuples correctly, but I seem to be following the syntax for indexing into a tuple, so I'm stumped. Can anyone steer me in the right direction?
但我认为这是因为第二个不正确。我的第一个想法是我没有正确比较元组,但我似乎遵循了索引元组的语法,所以我很难过。任何人都可以引导我朝着正确的方向前进吗?
回答by Dylan
Hopefully a few things to clear up your confusion:
希望有几件事可以消除您的困惑:
Matching in scala follows this general template:
Scala 中的匹配遵循以下通用模板:
x match {
case SomethingThatXIs if(SomeCondition) => SomeExpression
// rinse and repeat
// note that `if(SomeCondition)` is optional
}
It looks like you may have attempted to use the match/case expression as more of an if/else if/else kind of block, and as far as I can tell, the xdoesn't really matter within said block. If that's the case, you might be fine with something like
看起来您可能试图将 match/case 表达式用作更多的 if/else if/else 类型的块,据我所知,x在所述块中并不重要。如果是这样的话,你可能会喜欢这样的东西
case _ if (d(counter)._1 == key) => d(counter)._2
BUT
但
Some info on Lists in scala. You should always think of it like a LinkedList, where indexed lookup is an O(n)operation. Lists can be matched with a head :: tailformat, and Nilis an empty list. For example:
关于Lists 在 Scala 中的一些信息。您应该始终将其视为LinkedList,其中索引查找是一种O(n)操作。列表可以匹配一个head :: tail格式,并且Nil是一个空列表。例如:
val myList = List(1,2,3,4)
myList match {
case first :: theRest =>
// first is 1, theRest is List(2,3,4), which you can also express as
// 2 :: 3 :: 4 :: Nil
case Nil =>
// an empty list case
}
It looks like you're constructing a kind of ListMap, so I'll write up a more "functional"/"recursive" way of implementing your getmethod.
看起来您正在构建一种 ListMap,因此我将编写一种更“功能性”/“递归”的方式来实现您的get方法。
I'll assume that dis the backing list, of type List[(String, Any)]
我假设这d是支持列表,类型List[(String, Any)]
def get(key: String): Option[Any] = {
def recurse(key: String, list: List[(String, Any)]): Option[Any] = list match {
case (k, value) :: _ if (key == k) => Some(value)
case _ :: theRest => recurse(key, theRest)
case Nil => None
}
recurse(key, d)
}
The three case statements can be explained as follows:
这三个case语句可以解释如下:
1) The first element in listis a tuple of (k, value). The rest of the list is matched to the _because we don't care about it in this case. The condition asks if kis equal to the key we are looking for. In this case, we want to return the valuefrom the tuple.
1) 中的第一个元素list是 的元组(k, value)。列表的其余部分与 匹配,_因为在这种情况下我们不关心它。条件询问是否k等于我们正在寻找的键。在这种情况下,我们希望value从元组中返回。
2) Since the first element didn't have the right key, we want to recurse. We don't care about the first element, but we want the rest of the list so that we can recurse with it.
2)由于第一个元素没有正确的键,我们要递归。我们不关心第一个元素,但我们想要列表的其余部分,以便我们可以使用它进行递归。
3) case Nilmeans there's nothing in the list, which should mark "failure" and the end of the recursion. In this case we return None. Consider this the same as your counter > acccondition from your question.
3)case Nil表示列表中没有任何内容,应标记“失败”和递归结束。在这种情况下,我们返回None. 将此视为counter > acc与您问题中的情况相同。
Please don't hesitate to ask for further explanation; and if I've accidentally made a mistake (won't compile, etc), point it out and I will fix it.
请不要犹豫,要求进一步的解释;如果我不小心犯了错误(不会编译等),请指出,我会修复它。
回答by Don Mackenzie
I'm assuming that conditionally extracting part of a tuple from a list of tuples is the important part of your question, excuse me if I'm wrong.
我假设有条件地从元组列表中提取元组的一部分是您问题的重要部分,如果我错了,请原谅。
First an initial point, in Scala we normally would use AnyRef instead of Object or, if worthwhile, we would use a type parameter which can increase reuse of the function or method and increase type safety.
首先是初始点,在 Scala 中,我们通常会使用 AnyRef 而不是 Object ,或者,如果值得,我们将使用类型参数,它可以增加函数或方法的重用并增加类型安全性。
The three cases you describe can be collapsed into two cases, the first case uses a guard (the if statement after the pattern match), the second case matches the entire non-empty list and searches for a match between each first tuple argument and the key, returning a Some[T] containing the second tuple argument of the matching tuple or None if no match occurred. The third case is not required as the find operation traverses (iterates over) the list.
您描述的三种情况可以折叠为两种情况,第一种情况使用保护(模式匹配后的 if 语句),第二种情况匹配整个非空列表并搜索每个第一个元组参数和键,返回包含匹配元组的第二个元组参数的 Some[T] 或 None 如果没有匹配发生。第三种情况不是必需的,因为查找操作遍历(迭代)列表。
The map operation after the find is used to extract the second tuple argument (map on an Option returns an Option), remove this operation and change the method's return type to Option[(String, T)] if you want the whole tuple returned.
find 之后的 map 操作用于提取第二个元组参数(在 Option 上映射返回一个 Option),如果要返回整个元组,则删除此操作并将方法的返回类型更改为 Option[(String, T)] 。
def f[T](key: String, xs: List[(String, T)], initialCount: Int = 2): Option[T] = {
var counter = initialCount
xs match {
case l: List[(String, T)] if l.size < counter => None
case l: List[(String, T)] => l find {_._1 == key} map {_._2}
}
}
f("A", List(("A", 1), ("B", 2))) // Returns Some(1)
f("B", List(("A", 1), ("B", 2))) // Returns Some(2)
f("A", List(("A", 1))) // Returns None
f("C", List(("A", 1), ("B", 2))) // Returns None
f("C", Nil) // Returns None
回答by rlegendi
First, why are you using a Listfor that reason? What you need is definitely a Map. Its get()returns Noneif key is not found and Some(value)if it is found in it.
首先,你为什么要使用 a List?您需要的绝对是一个Map. 它的get()回报None,如果关键是没有找到,Some(value)如果在它发现。
Second, what is xin your example? Is it the list?
其次,x你的例子是什么?是名单吗?
Third, you cannot write case (log) => ..where logis a logical condition, it is in the form of case _ if (log) => ...(as Rex Kerr already pinted out in his comment).
第三,你不能写case (log) => ..where logis 一个逻辑条件,它的形式是case _ if (log) => ...(正如 Rex Kerr 已经在他的评论中指出的那样)。
Fouth, you need a recursive function for this (simply increasing the counter will call this only on the second element).
第四,你需要一个递归函数(简单地增加计数器只会在第二个元素上调用它)。
So you'll need something like this (if still prefer sticking to List):
所以你需要这样的东西(如果仍然喜欢坚持List):
def get(l: List[Tuple2[String, String]], key: String): Option[String] = {
if (l.isEmpty) {
None
} else {
val act = l.head
act match {
case x if (act._1 == key) => Some(act._2)
case _ => get(l.tail, key)
}
}
}

