从范围中删除值

时间:2014-02-26 02:25:42

标签: list scala

我有以下案例类:

case class objRanges(rangeVals:List[rangeNums])

其中rangeNums表示一系列值,也是一个案例类:

case class rangeNums(lowValue:Int, highValue:Int)

我想为objRanges实现一个减法方法,一个具有以下签名:

def -(numberRemove:Int): objRanges = {

然后将从列表rangeVals中的所有范围中删除该数字,将包含该数字的rangeNums拆分为两个rangeNums(一个从lowValue到n-1,另一个从n + 1到highValue)。使用for comprehension还是foldLeft会更容易实现吗?

例如,rangeVals目前包含元素:

[(1,3),(5,10)]

使用7作为参数调用 - 方法应返回带有元素的objRanges的新实例:

[(1,3),(5,6),(8,10)]

虽然减去一个范围下限的元素应该只增加一个下限,所以减去rangeVals中的5应返回:

[(1,3),(6,10)]

同样适用于上限。如果rangeVals目前持有:

[(1,3),(5,7)]

然后删除7应返回

[(1,3),(5,6)]

最后一个边界情况是一个范围内只有一个数字,并且该数字将被删除。例如,如果RangeVals当前持有:

[(1,3),(7,7)]

删除7应该只删除整个范围,返回一个范围等于的新实例:

[(1,3)]

如果我想要删除小于numberRemove的范围内的所有数字,解决方案会如何变化?

1 个答案:

答案 0 :(得分:2)

  1. 使用地图

    case class RangeNums(lowValue: Int, highValue: Int)
    
    case class ObjRanges(rangeVals: List[RangeNums]) {
      def -(n: Int): ObjRanges = {
        val res = rangeVals.map {
          case e @ RangeNums(l, h) =>
            if (n > l && n < h) RangeNums(l, n - 1) :: RangeNums(n + 1, h) :: Nil
            else if (n == l) RangeNums(l + 1, h) :: Nil
            else if (n == h) Nil
            else e :: Nil
        }.flatten
        ObjRanges(res)
      }
    }
    

    用REPL测试:

    scala> val l = RangeNums(0, 10) :: RangeNums(1, 3) :: Nil
    l: List[RangeNums] = List(RangeNums(0,10), RangeNums(1,3))
    
    scala>  val r = ObjRanges(l)
    r: ObjRanges = ObjRanges(List(RangeNums(0,10), RangeNums(1,3)))
    
    scala> r - 5
    res0: ObjRanges = ObjRanges(List(RangeNums(0,4), RangeNums(6,10), RangeNums(1,3)))
    
    scala> r - 2
    res1: ObjRanges = ObjRanges(List(RangeNums(0,1), RangeNums(3,10), RangeNums(1,1), RangeNums(3,3)))
    
    scala> r - 10
    res2: ObjRanges = ObjRanges(List(RangeNums(1,3)))
    
    scala> r - 0
    res3: ObjRanges = ObjRanges(List(RangeNums(1,10), RangeNums(1,3)))
    
  2. tailrec 解决方案:

    import scala.annotation.tailrec
    
    case class ObjRanges(rangeVals: List[RangeNums]) {
      def -(n: Int): ObjRanges = {
        @tailrec
        def minRec(n: Int, rem: List[RangeNums], accu: List[RangeNums]): List[RangeNums] =
          rem match {
            case (e @ RangeNums(l, h)) :: t =>
              val tmpRes =
                if (n > l && n < h) RangeNums(n + 1, h) :: RangeNums(l, n - 1) :: accu
                else if (n == l) RangeNums(l + 1, h) :: accu
                else if (n == h) accu
                else e :: accu
              minRec(n, t, tmpRes)
            case Nil =>
              accu
          }
        ObjRanges(minRec(n, rangeVals, Nil).reverse)
      }
    }
    
  3. 使用弃用

    case class ObjRanges(rangeVals: List[RangeNums]) {
       def -(n: Int): ObjRanges = {
         def minF(accu: List[RangeNums], e: RangeNums) = {
           val l = e.lowValue
           val h = e.highValue
           if (n > l && n < h) RangeNums(n + 1, h) :: RangeNums(l, n - 1) :: accu
           else if (n == l) RangeNums(l + 1, h) :: accu
           else if (n == h) accu
           else e :: accu
         }
         val res = (List[RangeNums]() /: rangeVals)((accu, e) => minF(accu, e))
         ObjRanges(res.reverse)
       }
    }