4

试图在这里处理模式匹配——来自 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

第三个也是:

scala> case _ => 计数器 += 1
:1: 错误:定义的非法开始

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

4

3 回答 3

6

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

scala 中的匹配遵循这个通用模板:

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

看起来您可能已尝试将 match/case 表达式用作更多的 if/else if/else 块,据我所知,x在所述块中并不重要。如果是这样的话,你可能会喜欢

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

Listscala 中关于 s 的一些信息。您应该始终将其视为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方法。

我假设这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)
}

这三个case语句可以解释如下:

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

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

3)case Nil表示列表中没有任何内容,应该标记“失败”和递归结束。在这种情况下,我们返回None. 考虑到这与counter > acc您的问题中的情况相同。

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

于 2012-09-19T18:42:25.223 回答
2

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

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

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

find 之后的 map 操作用于提取第二个元组参数(在 Option 上的 map 返回一个 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
于 2012-09-19T21:18:19.017 回答
0

首先,您为什么要使用 a List?你需要的绝对是一个Map. 如果未找到密钥并且在其中找到密钥,则get()返回。NoneSome(value)

其次,x你的例子是什么?是名单吗?

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

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

所以你需要这样的东西(如果仍然喜欢坚持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)
        }
    }
}
于 2012-09-19T18:36:47.520 回答