【问题标题】:Functional way to loop over nested list循环嵌套列表的功能方法
【发布时间】:2014-10-20 04:23:40
【问题描述】:

我被要求比较两棵树。如下所示:

case class Node(elem:String, child:List[Node])

为了比较树的每个元素,我有以下功能:

def compare(n1:Node, n2:Node): Boolean {
   if(n1.elem == n2.elem){
      return compare(n1.child, n2.child)
   }
}

def compare(c1:List[Node], c2:List[Node]): Boolean {
    while (c1.notEmpty) {
       //filter, map etc call function above to compare the element recursively
    }
}

基本上算法是针对 n1 中的每个元素,我们正在检查 n2 中的匹配。有人告诉我,这是非常必要的方式,而不是功能性的方式。什么是实现这种行为的实用方法。换句话说,我们如何在比较孩子列表时删除while循环?

【问题讨论】:

  • 您是否需要将第一个列表中的每个元素与第二个列表中的每个元素进行比较?或者只是两个第一个元素,两个第二个元素等等?
  • 是的,我想比较两个无序的子节点以查看天气一个列表包含与另一个列表完全相同的元素,一直到叶节点。

标签: scala functional-programming tail-recursion imperative-programming


【解决方案1】:

考虑压缩两个列表并使用forall,它只在它处理的每个谓词都评估为true 时才包含true;比如这样,

def compare(c1: List[Node], c2: List[Node]): Boolean = 
  (c1.sorted zip c2.sorted).forall(c => compare(c._1,c._2))

请注意,forall 将在遇到第一个 false 时停止评估。节点列表长度不等的情况可以用zipAll 解决,方法是为填充长度差异定义EmptyNode 类;两个空列表也可以与true 比较。

更新 根据@JohnB 的评论,排序节点列表以确保可靠性。

【讨论】:

  • 也许我误解了这个问题,但似乎 OP 想要将第一个列表中的每个节点与第二个列表中的每个其他节点进行比较。您的代码无法实现这一点,对吗?
  • 使用 zipAll 和一个 'emptynode' 实例来填充任何丢失的案例,它会比较它们。但是,我看到的问题是,如果它们具有所有相同的节点但顺序不同,则可以认为它们相等,因此首先排序或将两个列表都转换为集合并执行 set1.forall(c => s2.contains(c)) 和倒数。
  • @JohnB 同意,非常感谢 cmets。
  • 嗯,我认为 Seq 已经有了比较所有元素的 equals。您可以将List.corresponds 用于其他谓词。顺便说一句,OP 说孩子是无序的,但这听起来不正常。 (对不起,我看到了 OP 评论“完全相同的元素”,这不是一般的比较。)
  • zip 在我的情况下不起作用,我需要将外部列表的每个元素与内部列表中的每个元素进行比较。合并同一位置的节点是行不通的。
【解决方案2】:

如果我正确理解了您的问题,您希望将第一个列表的每个元素与第二个列表的每个元素进行比较。下面的代码实现了这一点。它通过尾递归摆脱了while 循环。

import scala.annotation.tailrec

def cmp(a:Int, b:Int) = a > b

@tailrec
def compare(xs: List[Int], ys: List[Int]): Boolean = xs match {
    case Nil => true
    case head :: tail if ys.forall(x => cmp(head, x)) => compare(tail, ys)
    case _ => false
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    • 2021-01-27
    • 2018-01-06
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多