Scala 中的模式匹配元组



试图在这里处理模式匹配 - 来自C++/Java背景,这对我来说非常陌生。

此分支的重点是检查元组列表d的每个成员[(字符串,对象)的格式]。我想定义三种情况。

1)如果此函数中的计数器大于列表的大小(在另一个称为acc中定义),则我不想返回任何内容(因为没有匹配项) 2)如果输入中给出的key与列表中的元组匹配,我想返回其值(或存储在tuple._2中的任何值)。 3)如果没有匹配,并且还有更多列表需要迭代,则递增并继续。

我的代码如下:

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
}

我的问题是,虽然第一种情况似乎编译正确,但第二种情况会抛出错误:

36:错误:")"预期,但"."找到。 case ((d(counter)._1) == key) => d(counter)._2

第三个也是:

斯卡拉> 案例 _ =>计数器 += 1 :1:错误:定义的非法开始

但我认为这是因为第二个不正确。我的第一个想法是我没有正确比较元组,但我似乎遵循了索引到元组的语法,所以我被难住了。谁能引导我走向正确的方向?

希望有几件事可以消除您的困惑:

scala 中的匹配遵循以下通用模板:

x match {
case SomethingThatXIs if(SomeCondition) => SomeExpression
// rinse and repeat
// note that `if(SomeCondition)` is optional
}

看起来您可能已经尝试将匹配/大小写表达式用作更多的 if/else if/else 类型的块,据我所知,x在所述块中并不重要。如果是这种情况,您可能会对类似的东西感到满意

case _ if (d(counter)._1 == key) => d(counter)._2

关于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
}

看起来您正在构建一种 ListMap,因此我将编写一种更"功能"/"递归"的方式来实现您的get方法。

我假设dList[(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)
}

这三种情况陈述可以解释如下:

1)list中的第一个元素是(k, value)元组。列表的其余部分与_匹配,因为在这种情况下我们不关心它。条件询问k是否等于我们正在寻找的密钥。在这种情况下,我们希望从元组中返回value

2)由于第一个元素没有正确的键,我们想要递归。我们不关心第一个元素,但我们想要列表的其余部分,以便我们可以递归。

3)case Nil意味着列表中没有任何内容,应该标记"失败"和递归的结束。在这种情况下,我们返回None.将此视为与问题中的counter > acc条件相同。

请不要犹豫,要求进一步的解释;如果我不小心犯了一个错误(不会编译等),指出来,我会修复它。

我假设有条件地从元组列表中提取元组的一部分是您问题的重要组成部分,如果我错了,请原谅。

首先是初始点,在 Scala 中,我们通常会使用 AnyRef 而不是 Object,或者,如果值得的话,我们会使用一个类型参数,它可以增加函数或方法的重用并提高类型安全性。

您描述的三种情况可以折叠为两种情况,第一种情况使用守卫(模式匹配后的 if 语句),第二种情况匹配整个非空列表并搜索每个第一个元组参数和键之间的匹配项,返回包含匹配元组的第二个元组参数的 Some[T],如果未发生匹配,则返回 None。第三种情况不是必需的,因为查找操作遍历(迭代)列表。

查找后的 map 操作用于提取第二个元组参数(选项 上的 map 返回一个选项),删除此操作,如果要返回整个元组,请将方法的返回类型更改为 Option[(字符串,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

首先,为什么出于这个原因使用List?你需要的绝对是Map.如果未找到键,则get()返回None,如果在其中找到键,则返回Some(value)

第二,你的例子中x是什么?是名单吗?

第三,你不能写case (log) => ..log是一个逻辑条件,它是以case _ if (log) => ...的形式写的(正如雷克斯·克尔在他的评论中已经指出的那样)。

Fouth,为此需要一个递归函数(只需增加计数器将仅在第二个元素上调用它)。

所以你需要这样的东西(如果仍然喜欢坚持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)
}
}
}

最新更新