Scala匹配错误案例预防

时间:2018-04-23 19:13:28

标签: scala list recursion combinations

我有这个函数基本上结合了列表列表,但你可以忽略它,因为这不是问题:

def combinationList[T](ls:List[List[List[T]]]) : List[List[List[T]]] = ls match {
 case head :: Nil  => for(x <- head) yield List(x)
 case head :: tail :: Nil =>
  for {
    hl <- head
    tl <- tail
    if tl.forall(te => !hl.contains(te))
  } yield List(hl, tl)
}

当我有一个带有两个子列表列表但是当我有两个以上时,它无法匹配。我显然需要递归地使用这个函数来做一个更一般的情况,并且我试图在函数的末尾添加以下案例:

case _ => combinationList(combinationList(ls.tail):::List(ls.head))

这里的逻辑是,假设我们有一个包含3个子列表的List,如下所示:

List ( List(1), List(2), List(3) )

当我第一次调用fucntion时,它只会在我提到的最后一种情况下匹配,因此,我将调用带有列表尾部的函数(List(2),List(3)),以及在该调用中,它将匹配第二种情况(head :: tail :: Nil),然后,当它返回时,它应该是单个List并且当被添加到列表的原始头部时(List(1) :: List(2 + 3))它应该匹配第二个条件。这里的问题是返回不是单个列表(List(2 + 3))而是列表的另一个组合(List(2),List(3))所以它显然会永远递归。我试图像这样修改案例:

combinationList(List(combinationList(ls.tail)):::List(ls.head))

但是它给了我一个错误(&#34; List [List [List [Any]]类型的表达式不符合List [List [List [T]]]&#34;

有什么想法吗?感谢。

[编辑:]此功能的目的是以这种方式组合列表:

simplified input: List( List(1,2), List(3), List(4))
simplified output: List( List(1,3,4), List(2,3,4))

real input: List(
             List(List(1), List(3), List(4)), 
             List(List(2), List(3), List(4))
            )
real expected output: List(
                       List(List(1), List(2)), 
                       List(List(1), List(3)), 
                       List(List(1), List(4)), 
                       List(List(3), List(2)), 
                       List(List(3), List(4)), 
                       List(List(4), List(2)), 
                       List(List(4), List(3))
                      )

使用实际输入,该函数能够返回预期的输出,它只在添加另一个子列表时失败,如下所示:

     input: List(
             List(List(1), List(2)), 
             List(List(3), List(4)),
             List(List(5))
            )

此处的预期输出为:

     expected output: List(
                       List(List(1), List(3), List(5)), 
                       List(List(1), List(4), List(5)), 
                       List(List(2), List(3), List(5)), 
                       List(List(2), List(4), List(5))
                      )

所以,组合的顺序并不重要,我可以负责:::尾巴或尾巴:::头,它是一样的。

1 个答案:

答案 0 :(得分:1)

我仍然不知道为什么你想要三层嵌套。但是,以下通用方法适用于所有示例,包括整数和列表:

def combinationList[T](ls: List[List[T]]): List[List[T]] = {
  def recHelper(remainingLs: List[List[T]], blacklist: Set[T]): List[List[T]] = {
    remainingLs match {
      case Nil => List(Nil)
      case h :: t => for { 
        x <- h.filterNot(blacklist.contains)
        xs <- recHelper(t, blacklist + x)
      } yield x :: xs
    }
  }
  recHelper(ls, Set.empty)
}

此实现不会过滤掉与! .contains的任何组合,而是会维护一组列入黑名单的元素,并且不会首先生成无效组合。

一些例子:

def showExample[T](input: List[List[T]]): Unit = {
  println("=" * 60)
  println(input)
  println("-" * 60)
  for (c <- combinationList(input)) {
    println("  " + c)
  }
}
showExample(List(List(1, 2), List(3), List(4)))
showExample(List(List(1, 2, 3), List(2, 3, 4), List(2, 3, 5)))
showExample(List(
  List(List(1), List(3), List(4)), 
  List(List(2), List(3), List(4))
))
showExample(List(
  List(List(1), List(2)), 
  List(List(3), List(4)),
  List(List(5))
))

输出:

============================================================
List(List(1, 2), List(3), List(4))
------------------------------------------------------------
  List(1, 3, 4)
  List(2, 3, 4)
============================================================
List(List(1, 2, 3), List(2, 3, 4), List(2, 3, 5))
------------------------------------------------------------
  List(1, 2, 3)
  List(1, 2, 5)
  List(1, 3, 2)
  List(1, 3, 5)
  List(1, 4, 2)
  List(1, 4, 3)
  List(1, 4, 5)
  List(2, 3, 5)
  List(2, 4, 3)
  List(2, 4, 5)
  List(3, 2, 5)
  List(3, 4, 2)
  List(3, 4, 5)
============================================================
List(List(List(1), List(3), List(4)), List(List(2), List(3), List(4)))
------------------------------------------------------------
  List(List(1), List(2))
  List(List(1), List(3))
  List(List(1), List(4))
  List(List(3), List(2))
  List(List(3), List(4))
  List(List(4), List(2))
  List(List(4), List(3))
============================================================
List(List(List(1), List(2)), List(List(3), List(4)), List(List(5)))
------------------------------------------------------------
  List(List(1), List(3), List(5))
  List(List(1), List(4), List(5))
  List(List(2), List(3), List(5))
  List(List(2), List(4), List(5))

一些提示:

  • 更通用的代码版本通常更容易编写,因为如果有更多的约束,那么做错的可能性就会减少。在这种情况下,三重嵌套似乎是不必要的。
  • 基本案例是空列表,而不是包含一个元素的列表
  • 递归必须适用于任意长度的列表,但x :: y :: Nil仅匹配长度为2的列表。