Scala 如何在功能上合并列表中的重叠数字范围
我有许多需要合并的范围对象,以便所有重叠范围消失:Scala 如何在功能上合并列表中的重叠数字范围,scala,functional-programming,scala-collections,Scala,Functional Programming,Scala Collections,我有许多需要合并的范围对象,以便所有重叠范围消失: case class Range(from:Int, to:Int) val rangelist = List(Range(3, 40), Range(1, 45), Range(2, 50), etc) 以下是范围: 3 40 1 45 2 50 70 75 75 90 80 85 100 200 一旦完成,我们将得到: 1 50 70 90 100 200
case class Range(from:Int, to:Int)
val rangelist = List(Range(3, 40), Range(1, 45), Range(2, 50), etc)
以下是范围:
3 40
1 45
2 50
70 75
75 90
80 85
100 200
一旦完成,我们将得到:
1 50
70 90
100 200
命令式算法:
允许在迭代时按索引删除项目,但这样就不再具有功能了。我喜欢这些类型的谜题:
case class Range(from:Int, to:Int) {
assert(from <= to)
/** Returns true if given Range is completely contained in this range */
def contains(rhs: Range) = from <= rhs.from && rhs.to <= to
/** Returns true if given value is contained in this range */
def contains(v: Int) = from <= v && v <= to
}
def collapse(rangelist: List[Range]) =
// sorting the list puts overlapping ranges adjacent to one another in the list
// foldLeft runs a function on successive elements. it's a great way to process
// a list when the results are not a 1:1 mapping.
rangelist.sortBy(_.from).foldLeft(List.empty[Range]) { (acc, r) =>
acc match {
case head :: tail if head.contains(r) =>
// r completely contained; drop it
head :: tail
case head :: tail if head.contains(r.from) =>
// partial overlap; expand head to include both head and r
Range(head.from, r.to) :: tail
case _ =>
// no overlap; prepend r to list
r :: acc
}
}
case类范围(从:Int到:Int){
断言(来自以下是我的解决方案:
def merge(ranges:List[Range]) = ranges
.sortWith{(a, b) => a.from < b.from || (a.from == b.from && a.to < b.to)}
.foldLeft(List[Range]()){(buildList, range) => buildList match {
case Nil => List(range)
case head :: tail => if (head.to >= range.from) {
Range(head.from, head.to.max(range.to)) :: tail
} else {
range :: buildList
}
}}
.reverse
merge(List(Range(1, 3), Range(4, 5), Range(10, 11), Range(1, 6), Range(2, 8)))
//List[Range] = List(Range(1,8), Range(10,11))
def合并(范围:列表[范围])=范围
.sortWith{(a,b)=>a.frombuildList匹配{
案例无=>列表(范围)
case head::tail=>if(head.to>=range.from){
范围(head.from,head.to.max(Range.to))::tail
}否则{
范围::构建列表
}
}}
.反向
合并(列表(范围(1,3)、范围(4,5)、范围(10,11)、范围(1,6)、范围(2,8)))
//列表[范围]=列表(范围(1,8),范围(10,11))
尝试尾部递归。(如果尾部递归优化没有发生,则只需要注释来警告您;无论您是否注释,编译器都会在可以的情况下进行注释。)
这假设rs
是按范围初始元素排序的。最好只让x包含y。从合并排序并传递到折叠
。如果不这样做,则运行时是O(n^2)
而不是O(n log n)
应该这样。您应该在collapse
方法上添加@annotation.tailrec
,这样,如果编译器无法执行尾部调用优化,它将发出错误。@dave-如果不确定,可以添加此批注。在这种情况下,我可以肯定,但最好知道批注的存在。@RexKerr-我已经看到了足够多的情况,代码看起来应该优化,但没有看到我在假设TCO时总是添加注释。例如,当定义为类上的非私有、非最终方法时,collapse
函数将不会优化。非常感谢。您需要在之后进行反转,以便将其恢复到排序顺序供参考。
import annotation.{tailrec => tco}
@tco final def collapse(rs: List[Range], sep: List[Range] = Nil): List[Range] = rs match {
case x :: y :: rest =>
if (y.from > x.to) collapse(y :: rest, x :: sep)
else collapse( Range(x.from, x.to max y.to) :: rest, sep)
case _ =>
(rs ::: sep).reverse
}
def merge(rs: List[Range]): List[Range] = collapse(rs.sortBy(_.from))