【问题标题】:for comprehension in scala with recursive call用递归调用在scala中理解
【发布时间】:2017-01-04 18:57:55
【问题描述】:

我正在为 coursera 课程“scala 中的函数式编程”做最后一个项目。我需要实现一个称为组合的函数,该函数接受一个字符出现列表并输出所有可能的字符出现子集。例如,出现列表List(('a', 2), ('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))
)

我解决这个问题的方法是遍历每个字符(例如“a”),并获取其可能出现的次数(从 0 到 2),并将其准备到当前子集。然后继续下一个字符并重复,直到我到达列表的末尾,这被基本情况捕获。我用如下的理解实现了这个:

type Occurrences = List[(Char, Int)]

def combinations(occurrences: Occurrences): List[Occurrences] =
  if (occurrences == List()) List() // base case
  else
    for {
      (c, n) <- occurrences
      subc <- combinations((occurrences.toMap - c).toList)
      i <- 0 to n
    } yield {
      if (i == 0) subc // not including c in the subset
      else (c, i) :: subc // including c in the subset
    }

当我调用combinations(List(('a', 2), ('b', 2)) 时,这个函数总是给我一个空列表。任何想法为什么会这样?

【问题讨论】:

  • 我意识到“解决方案”是错误的,即使它给了我预期的结果,因为我循环遍历集合中的元素的方式会有很多重复。我不明白为什么我会得到一个空列表。

标签: scala for-comprehension


【解决方案1】:

意外输出的原因在这里:

subc <- combinations((occurrences.toMap - c).toList)

这将递归,加载堆栈帧,直到最终返回基本情况List()。现在,请记住,在 for 理解中,生成器 (&lt;-) 是通过 mapflatMap 实现的,一旦你映射到一个空集合上,你就完成了。

List[Int]().map(_ + 1).foreach(_ => println("got it"))  // no output

所以下面的生成器 i &lt;- 0 to n 没有被调用,yield 没有任何东西,空的 List() 是唯一返回的东西。然后栈帧弹出,接收到空的List()

【讨论】:

    【解决方案2】:

    问题出在这条线:

    subc <- combinations((occurrences.toMap - c).toList)
    

    在基本情况上方的调用中,这被评估为List(),这会妨碍您的理解:

    scala> for {a <- 0 to 3; b <- List()} yield a
    res0: scala.collection.immutable.IndexedSeq[Int] = Vector()
    

    这使得该调用返回 List() 等等,这意味着您在调用堆栈中一直返回空列表,这就是为什么您会在顶部得到一个 List()

    【讨论】:

      猜你喜欢
      • 2015-12-05
      • 2021-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-30
      相关资源
      最近更新 更多