【问题标题】:Scala matching List of tuples with guardsScala 匹配带有保护的元组列表
【发布时间】:2016-11-04 10:39:49
【问题描述】:

我是 Scala 新手。作为一个练习,我试图在一个带有警卫的元组列表上编写一个匹配语句。我知道地图可以解决问题,但我正在尝试了解模式匹配。

我试图编写一个以List[(Char, Int)] 作为参数的函数。该函数对条目进行排序,如果两个条目具有相同的键值,则将它们相加。所以下面的参数List(('q', 1'), ('a', 1), ('c', 2), ('a', 2), ('c', 1)) 会变成List(('a', 3), ('c', 3'), ('q', 1))

我提供以下代码:

def sortAndAggregateList(chars: List[(Char, Int)]) : List[(Char, Int)] = {
  chars match {
    case (charP1, numP1) :: (charP2, numP2) :: (x : List[(String, Int)]) if (charP1 > charP2) =>
      sortAndAggregateList((charP2, numP2) :: (charP1, numP1) :: x)
    case (charP1, numP1) :: (charP2, numP2) :: (x : List[(String, Int)]) if (charP1 < charP2) =>
      sortAndAggregateList((charP1, numP1) :: (charP2, numP2) :: x)
    case (charP1, numP1) :: (charP2, numP2) :: (x : List[(String, Int)]) if (charP1 == charP2) =>
      sortAndAggregateList((charP1, numP1 + numP2) :: x)
    case Nil =>
      Nil
  }
}

但我收到以下警告:

:14: 警告:没有结果的类型测试:List[(Char, Int)] 类型的值不能也是 List[(String, Int)] (List[(String, Int)] 的底层)(但仍然可能匹配它的擦除)

我尝试删除列表,但如果这样做,我会收到一个错误,即 x 的类型为 Any

有什么建议吗?

【问题讨论】:

  • 查看错误消息:您正在匹配 chars,这是一个 List[(Char,Int)],但在您希望 xList[(String, Int)] 的模式中。

标签: scala pattern-matching pattern-guards


【解决方案1】:

错误是您在每个 case 语句之后执行的类型检查 (: List[(String, Int)])。

如果您将代码更改为以下内容,错误就会消失:

def sortAndAggregateList(chars: List[(Char, Int)]) : List[(Char, Int)] = {
  chars match {
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 > charP2) =>
      sortList(p1 :: p2 :: x)
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 < charP2) =>
      sortList(p2 :: p1 :: x)
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 == charP2) =>
        val p3: (Char, Int) = (charP1, numP1 + numP2)
        sortList(p3 :: x)
    case x =>
      x
    case Nil =>
      Nil
  }
}

之后你会发现编译器告诉你 p1 和 p2 是未定义的。要解决此问题,您需要将它们设置为 p1 = (charP1, numP1) 和 p2 = (charP2, numP2)。 要使用您的语法解决此问题,您可以执行以下操作:

def sortAndAggregateList(chars: List[(Char, Int)]) : List[(Char, Int)] = {
  chars match {
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 > charP2) =>
      sortList((charP1, numP1) :: (charP2, numP2) :: x)
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 < charP2) =>
      sortList((charP2, numP2) :: (charP1, numP1) :: x)
    case (charP1, numP1) :: (charP2, numP2) :: x if (charP1 == charP2) =>
        val p3: (Char, Int) = (charP1, numP1 + numP2)
        sortList(p3 :: x)
    case x =>
      x
    case Nil =>
      Nil
  }
}

现在唯一缺少的链接是您尚未添加的 sortList 函数。 我不确定这是否可行,因为我认为是这样的:

case x => x

应该是:

case x :: Nil => x :: Nil

否则 x 将匹配任何内容。这也使您有可能删除案例:

case Nil => Nil

如果您不想删除大小写 x => x

【讨论】:

  • 是的,你是对的,这就是为什么我补充说它匹配任何东西,甚至是 Nil。
  • case Nil => Nil 是多余的
【解决方案2】:

x 之后的额外类型注释是不必要的,也是错误的。

删除这个

(x : List[(String, Int)])

改为使用(非强制,可以省略类型注解)

(x : List[(Char, Int)])

功能齐全

  def sortAndAggregateList(chars: List[(Char, Int)]): List[(Char, Int)] = chars match {
    case (charP1, numP1) :: (charP2, numP2) :: x if charP1 > charP2 =>

      sortAndAggregateList((charP2, numP2) :: (charP1, numP1) :: x)

    case (charP1, numP1) :: (charP2, numP2) :: x if charP1 < charP2 =>

      sortAndAggregateList((charP1, numP1) :: (charP2, numP2) :: x)

    case (charP1, numP1) :: (charP2, numP2) :: x if charP1 == charP2 =>

      sortAndAggregateList((charP1, numP1 + numP2) :: x)

    case x => x
  }

如果考虑折叠元组,代码会更简洁

  def sortAndAggregateList(chars: List[(Char, Int)]): List[(Char, Int)] = chars match {
    case a :: b :: x if a._1 > b._2 =>

      sortAndAggregateList(b :: a :: x)

    case a :: b :: x if a._1 < b._1 =>

      sortAndAggregateList(a :: b :: x)

    case a :: b :: x if a._1 == b._1 =>

      sortAndAggregateList((a._1, (a._2 + b._2)) :: x)

   case x => x

  }

case case x =&gt; x 将匹配列表 Nil 大小写和具有一个元素大小写的列表。

【讨论】:

  • 这个函数有一个弱点。它不适用于仅包含一个条目的列表,例如: List(("t", 1))
猜你喜欢
  • 1970-01-01
  • 2020-02-13
  • 1970-01-01
  • 2015-05-30
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 2014-08-27
  • 1970-01-01
相关资源
最近更新 更多