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  
命令式算法:

  • Pop()指定第一个范围obj,并遍历列表的其余部分,将其与其他每个范围进行比较
  • 如果有重叠项, 将它们合并在一起(这将生成一个新的范围实例),并从源列表中删除2个合并候选对象
  • 在列表的末尾,将范围对象(通过合并可能已更改多次)添加到最终结果列表中
  • 对剩余的下一项重复此操作
  • 一旦源列表为空,我们就完成了
  • 为此,必须创建大量临时变量、索引循环等

    所以我想知道是否有更实用的方法

    乍一看,源集合必须能够像堆栈一样提供pop()PLUS
    允许在迭代时按索引删除项目,但这样就不再具有功能了。

    我喜欢这些类型的谜题:

    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))