如何使用for / yield编写Scala递归?

时间:2016-02-01 20:19:20

标签: scala for-loop recursion yield

我有以下列对(key,id):

val pairs =  List(('a',1), ('a',2), ('b',1), ('b',2))

当键不同时,我需要生成所有对的组合 所以预期的输出是:

List(
  List(),
  List(('a', 1)),
  List(('a', 2)),
  List(('b', 1)),
  List(('a', 1), ('b', 1)),
  List(('a', 2), ('b', 1)),
  List(('b', 2)),
  List(('a', 1), ('b', 2)),
  List(('a', 2), ('b', 2))
)

注意(List(('a',1),('a',2))不应该是输出的一部分,因此使用Scala List.combinations不是一个选项

我目前有以下代码:

def subSeq (xs: List[(Char, Int)]): List[(Char,Int)] = {
  xs match {
    case Nil => List()
    case y::ys => {
      val eh = xs.filter (c => c._1 == y._1)
      val et = xs.filter (c => c._1 != y._1)
      for (z: (Char,Int) <- eh) yield z :: subSeq(et)
    }
  }
}

但我收到错误List[List[(Char,Int)]] does not match List[(Char,Int)]

2 个答案:

答案 0 :(得分:0)

你可能想要做的是:

def subSeq (xs: List[(Char, Int)]): List[List[(Char,Int)]] = {
  xs match {
    case Nil => List(List())
    case y::ys => {
      val eh: List[(Char, Int)] = xs.filter (c => c._1 == y._1)
      val et = xs.filter (c => c._1 != y._1)
      val t = subSeq(et)
      t ++ (for {
        z: (Char,Int) <- eh
        foo <- t
      } yield z :: foo)
    }
  }
}

您的方法必须返回列表列表,因为这是您感兴趣的内容。因此,在构建组合时,您必须迭代递归步骤的结果。

使用API​​函数的方法是这样做:

val sets = (0 to 2).flatMap{pairs.combinations}.toSet
sets.map{_.toMap}

或者,如果您需要输出作为列表:

sets.map{_.toMap.toList}.toList

显然,这将构建比您最初需要的更多组合,然后过滤掉东西。如果性能是一个问题并且输入不包含任何冗余,那么直接实现可能会更好。

答案 1 :(得分:0)

最终我使用了Scala的combinations函数并通过此过滤函数过滤掉了非相关匹配

def filterDup(xs: List[(Char,Int)]) : Boolean = {
    xs.map(x => x._1).size == xs.map(x => x._1).toSet.size
  }

并将其用作以下内容:

((0 to 3).flatMap(pairs.combinations(_)) filter( filterDup(_))).toList