我有以下案例类:
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的范围内的所有数字,解决方案会如何变化?
答案 0 :(得分:2)
使用地图:
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)))
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)
}
}
使用弃用:
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)
}
}