簡體   English   中英

使用 Spark Scala 進行間隔合並

[英]Interval merge using Spark Scala

我有我想在有重疊時合並的間隔列表。

示例: List((1,1),(2,2),(4,4),(5,5))這里想要的輸出是List((1,2),(4,5))

我有一個價值 2.5GB 的數字列表,我想將其轉換為 Ranges 。

注意:輸入列表中沒有重復項

腳步

  1. 輸入: List[Int] 。
  2. 映射到元組列表: List((a,a),(b,b), ...) 。
  3. 用范圍合並邏輯減少它。
val l = List(List((1,1)),List((2,2)),List((4,4)),List((5,5)))
val list =sc.parallelize(l)

def merge(r1:(Int,Int),r2:(Int,Int))  :(Int,Int)  = {
    if(r1._2+1==r2._1) (r1._1,r2._2)
    else if(r2._2+1 == r1._1) (r2._1,r1._2)
    else null
}

val res = list.reduce((x,y) =>{
   x.map(r1 => {
        y.map(r2 => {
            val m = merge(r1,r2)
             m match {
                case null => List(r1,r2)
                case _ => List(m)
             }
         }).flatten
    }).flatten
})

res: List[(Int, Int)] = List((4,5), (2,2), (1,2))

實際輸出是res: List[(Int, Int)] = List((4,5), (2,2), (1,2))其中正如我所期望的List((4,5),(1,2))

編輯:我的解決方案

我嘗試了以下代碼。 似乎輸入很小,但我的原始數據花費的時間太長。 還有比這更好的解決方案嗎?

def overlap(x: (Int,Int),y:(Int,Int)) = {
    if(x._2==y._1) (x._1,y._2)
    else if(x._1==y._2) (y._1,x._2)
    else null
}

def isOverlapping(x: (Int,Int),y:(Int,Int)) = {
    x._1 == y._1 || x._1 == y._2 || x._2==y._1 || x._2==y._2 
}

val res = list.reduce((x,y) =>{
  val z =  x.map(r1 => {
        y.map(r2 => {
            val m = merge(r1,r2)
             m match {
                case null => List(r1,r2)
                case _ =>{
                     List(m)
                }
             }
         }).flatten
    }).flatten
    
//-------compressing the accumulated list z to merge overlapping tuples

    z.foldLeft(List[(Int,Int)]()) { (acc, i) => {
    if (!acc.exists(isOverlapping(i, _)))
        i +: acc
      else
        acc.map(x => {
            val m = overlap(x,i)
             m match {
                case null => x
                case _ => m
             }
        })
    }}
//---------

})


res: List[(Int, Int)] = List((4,5), (1,2))

我最近解決了這個問題。 我使用 List[List[Int]] 作為我的收藏。

我的方法是使用排序集合,這樣當我們實際嘗試減少重疊間隔時,我們利用排序(我們使用開始位置作為鍵開始排序,但如果兩個開始位置相等,我們使用結束位置)並且可以以 O(nlogn) 的復雜度完成問題。 我專門使用了排序集,以便如果有重復的間隔,則在我們進一步減少它們之前將其刪除。

一旦集合被排序,那么我們只需要檢查相鄰對是否重疊。 我通過檢查 1stPair.end >= 2ndPair.Start 來做到這一點。 如果為真,則表示 Pairs 重疊,我們可以通過 (1stPair.start,max(1stPair.end,2ndPair.end)) 將這 2 Pairs 更改為 1 pairs。 這里不需要檢查對之間的開始間隔,因為它是有序的,所以 2ndPair.start 將始終 >= 1stPair.start。 這是我們使用排序集合獲得的節省。

我假設,如果這些對彼此相鄰而沒有重疊,我仍然認為這是重疊並減少了它。 例如([1,2],[2,3] 減少到 [1,3])。 整個解決方案的時間復雜度就是排序的復雜度。 由於我使用SortedSet自帶的內置排序算法,我猜它提供了最快的排序(O(nlogn)。為了減少間隔,它只通過1次通過集合,所以復雜度是線性的。比較這些復雜度和“O( n)”不如“O(nlogn)”重要。所以整體復雜度是“O(nlogn)”。這是在Scala Worksheet中運行並檢查其他幾個輸入,它工作正常。

 import scala.collection.SortedSet
  object order extends Ordering[List[Int]] {
    override def compare(a: List[Int], b: List[Int]): Int = {
      if (a(0) != b(0)) a(0) - b(0)
      else a(1) - b(1)
    }
  }
  val sorted_input = SortedSet(List(6, 9), List(1, 4), List(3, 5), List(8, 12))(order)
  def deduce(list: List[List[Int]], pair: List[Int]): List[List[Int]] = {
    val finalList = (pair, list) match {
      case (pair, head :: tail) if (pair(0) <= head(1)) => List(head(0), if (pair(1) > head(1)) pair(1) else head(1)) :: tail
      case (pair, emptyList)                            => pair :: emptyList
    }
    finalList
  }                                              
  sorted_input.foldLeft(List[List[Int]]())(deduce) //> res0: List[List[Int]] = List(List(6, 12), List(1, 5))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM