2017-12-02 373 views
2

我有如圖逗號分隔的數字數組:將多個連續的條目中的Scala /火花

一個:{108,109,110,112,114,115,116,118}

我所需要的輸出是這樣的:

一個:{108-110,112,114-116,118}

我試圖將連續的數字與之間的「 - 」進行分組。 例如,108,109,110是連續數字,所以我得到108-110。 112是單獨的條目; 114,115,116再次代表一個序列,所以我得到114-116。 118是分開的,如此對待。

我在Spark中這樣做。我寫以下代碼:

import scala.collection.mutable.ArrayBuffer 

def Sample(x:String):ArrayBuffer[String]={ 
    val x1 = x.split(",") 
    var a:Int = 0 
    var present="" 
    var next:Int = 0 
    var yrTemp = "" 
    var yrAr= ArrayBuffer[String]() 
    var che:Int = 0 
    var storeV = "" 
    var p:Int = 0 
    var q:Int = 0 

    var count:Int = 1 

    while(a < x1.length) 
    { 
     yrTemp = x1(a) 

     if(x1.length == 1) 
     { 
      yrAr+=x1(a) 
     } 
     else 
     if(a < x1.length - 1) 
     { 
      present = x1(a) 
      if(che == 0) 
      { 
       storeV = present 
      } 

      p = x1(a).toInt 
      q = x1(a+1).toInt 

      if(p == q) 
      { 
       yrTemp = yrTemp 
       che = 1 
      } 
      else 
      if(p != q) 
      { 
       yrTemp = storeV + "-" + present 
       che = 0 
       yrAr+=yrTemp 
      } 

     } 
     else 
      if(a == x1.length-1) 
      { 
       present = x1(a) 
       yrTemp = present 
       che = 0 
       yrAr+=yrTemp 
      } 
     a = a+1 
    } 
yrAr 
} 
val SampleUDF = udf(Sample(_:String)) 

我正在輸出如下:

一個:{108-108,109-109,110-110,112,114-114,115- 115,116-116,118}

我無法弄清楚我哪裏出錯了。你能幫我解決這個問題嗎? TIA。

+1

請解釋導致您的預期輸出的規則。而且,這不是真的與spark相關,它只是一個scala問題 –

+0

@RaphaelRoth我在我的問題中編輯了規則。 –

回答

2

這裏的另一種方式:

def rangeToString(a: Int, b: Int) = if (a == b) s"$a" else s"$a-$b" 

def reduce(xs: Seq[Int], min: Int, max: Int, ranges: Seq[String]): Seq[String] = xs match { 
    case y +: ys if (y - max <= 1) => reduce(ys, min, y, ranges) 
    case y +: ys     => reduce(ys, y, y, ranges :+ rangeToString(min, max)) 
    case Seq()      => ranges :+ rangeToString(min, max) 
} 

def output(xs: Array[Int]) = reduce(xs, xs.head, xs.head, Vector())//.toArray 

你可以測試:

println(output(Array(108,109,110,112,114,115,116,118))) 
    // Vector(108-110, 112, 114-116, 118) 

基本上這是一個尾遞歸函數 - 即你把你的「變量」作爲輸入,然後調用本身在每個循環更新的「變量」。所以這裏xs是你的數組,minmax是用來跟蹤到目前爲止最低和最高數字的整數,而ranges是當需要時被添加到的字符串的輸出序列。

的第一圖案(y是第一要素,並ys是該序列的其餘部分 - 因爲這是怎麼+:提取的作品),如果有至少一個元素的匹配(ys可以是一個空列表),它遵循從之前的最大值開始。

第二個是如果它不繼續,並且需要重置最小值並將完成的範圍添加到輸出。

第三種情況是我們已經到了輸入的結尾並輸出結果,而不是再次調用循環。

互聯網業力指向任何人誰可以計算出如何消除重複ranges :+ rangeToString(min, max)

1

這裏是一個解決方案:

def combineConsecutive(s: String): Seq[String] = { 
    val ints: List[Int] = s.split(',').map(_.toInt).toList.reverse 

    ints 
    .drop(1) 
    .foldLeft(List(List(ints.head)))((acc, e) => if ((acc.head.head - e) <= 1) 
     (e :: acc.head) :: acc.tail 
    else 
     List(e) :: acc) 
    .map(group => if (group.size > 1) group.min + "-" + group.max else group.head.toString) 
} 


val in = "108,109,110,112,114,115,116,118" 

val result = combineConsecutive(in) 

println(result) // List(108-110, 112, 114-116, 118) 

}

該解決方案部分使用代碼來自這個問題:Grouping list items by comparing them with their neighbors

+0

謝謝@raphael的解決方案。作爲一個初學者,我從來沒有想過這可以輕鬆完成。再次感謝! –