【问题标题】:How to write Scala recursion with for/yield?如何使用 for/yield 编写 Scala 递归?
【发布时间】:2016-05-10 10:28:53
【问题描述】:

我有以下对 (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)]

【问题讨论】:

  • 您的返回类型与您提供的输出不符。如果你想要List(List(), ... 作为输出,也许你应该返回List[List[(Char, Int)]]?。还有一个提示:您可以使用list.flattenList[List[T]] 翻译成List[T]
  • flatten 确实解决了类型不匹配但产生错误的结果 - List((a,1), (b,1), (c,1), (b,2), (c,1), (a,2), (b,1), (c,1), (b,2), (c,1)) 这是对列表而不是组合列表列表

标签: scala for-loop recursion yield


【解决方案1】:

你可能想要做的是:

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

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

【讨论】:

    【解决方案2】:

    最终我使用了 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
    

    【讨论】:

      猜你喜欢
      • 2020-12-02
      • 2014-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多