【问题标题】:Scala: Is there an elegant way to compare values in pattern matching?Scala:有没有一种优雅的方式来比较模式匹配中的值?
【发布时间】:2017-12-15 03:03:58
【问题描述】:

我正在尝试使用 scala 实现一个简单的二叉树。 我的树定义如下:

abstract class Tree[T <: Ordered[T]]
case class Node[T <: Ordered[T]](v:T, l:Tree[T], r:Tree[T]) extends Tree[T]
case class Leaf[T <: Ordered[T]](v:T) extends Tree[T]

我正在尝试实现一种方法来找到树中的最小值。方法实现如下:

def minInTree[T <: Ordered[T]](t: Tree[T]): T = t match {

    case Node(v, lft, rght) if minInTree(lft) > minInTree(rght) => {
        val mLft = minInTree(lft)
        val mRght = minInTree(rght)
        if (v > mRght)
           mRght
        else
           v
    }

    case Node(v, lft, rght) if minInTree(lft) <= minInTree(rght) => {
        val mLft = minInTree(lft)
        val mRght = minInTree(rght)
        if (v > mLft)
            mLft
        else
            v
    }
    case Leaf(lf) => lf
}

我发现minInTree(lft)minInTree(rght) 被多次调用,我认为这是缓慢而丑陋的。比较使用了多个if-else子句,我认为这也很丑。

有没有什么优雅的方式来重构代码? 任何提示表示赞赏。

【问题讨论】:

    标签: scala pattern-matching


    【解决方案1】:

    如果您要使用 Ordering 类型类,则可以在值上使用 min() 方法,这会使事情变得更加优雅。

    abstract class Tree[T: Ordering]
    case class Node[T: Ordering](v:T, l:Tree[T], r:Tree[T]) extends Tree[T]
    case class Leaf[T: Ordering](v:T) extends Tree[T]
    
    def minInTree[T](t: Tree[T])(implicit ev:Ordering[T]): T = t match {
      case Node(v, lft, rght) => ev.min(v, ev.min(minInTree(lft), minInTree(rght)))
      case Leaf(lf) => lf
    }
    

    导入一些方便的隐式,min 评估更加清晰。

    import Ordering.Implicits._
    def minInTree[T: Ordering](t: Tree[T]): T = t match {
      case Node(v, lft, rght) => v min minInTree(lft) min minInTree(rght)
      case Leaf(lf) => lf
    }
    

    它还提供了基本的比较操作。 (&lt;&gt;等)

    【讨论】:

      【解决方案2】:

      我只是稍后移动比较,否则我认为没有什么好方法可以实现这一点:

      case Node(v, lft, rght) => {
          val mLft = minInTree(lft)
          val mRght = minInTree(rght)
          if (mLft > mRght) ... // corresponds to if minInTree(lft) > minInTree(rght) => ...
          else ... // corresponds to your second branch
      }
      

      【讨论】:

        【解决方案3】:

        正如 jwvh 所写,您可以使用 Ordering 来获得更简洁的代码。 另一种获得更简洁代码的方法是使用继承代替模式匹配:

        println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet
        
        sealed trait Tree[T] {
            def min(implicit ev : Ordering[T]) : T
        }
        
        case class Node[T](value : T, left : Tree[T], right : Tree[T]) extends Tree[T] {
            def min(implicit ev : Ordering[T]) : T = ev.min(value, ev.min(left.min(ev), right.min(ev)))
        }
        
        case class Leaf[T](value : T) extends Tree[T] {
            def min(implicit ev : Ordering[T]) : T = value
        }
        
        val tree = Node(17, Leaf(2), Node(4, Leaf(10), Leaf(8)))
                                                      //> tree  : testTree#626615.Node#1020777[Int#918] = Node(17,Leaf(2),Node(4,Leaf(
                                                      //| 10),Leaf(8)))
        tree.min                                  //> res0: Int#918 = 2
        

        我更喜欢仅在需要时为 min 方法添加 Ordering 类型类。 如果你还想要一个函数,那很容易:

        def minTree[T](t : Tree[T])(implicit ev : Ordering[T]) = t.min
        minTree(tree)                             //> res1: Int#918 = 2
        

        【讨论】:

          猜你喜欢
          • 2013-04-16
          • 1970-01-01
          • 2011-09-18
          • 1970-01-01
          • 2010-09-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-24
          相关资源
          最近更新 更多