2017-12-02 8 views
2

I有し示すようにカンマで区切られた数字の配列:スパーク/ 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は別個であり、そのまま扱われる。

私はこれをスパークで行っています。

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

期待される出力につながるルールを説明してください。そして、これは本当に火花に関連するものではなく、ちょうど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は必要なときに追加されるStringsの出力シーケンスです。

第一のパターン(yが最初の要素であること、およびysはシーケンスの残りが - それはどのように+:抽出作品だから)少なくとも一つの要素があるかどうマッチさ(ysは空リストを指定できます)、それは以下の前の最大値からオンにします。

2つ目は、それに続くものではなく、最小値をリセットして、出力に完成した範囲を追加する必要がある場合です。

3番目のケースでは、入力の最後にループを再度呼び出すのではなく、結果を出力します。

インターネットカルマは、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に感謝します。これを初心者にすれば、簡単にやり遂げることはできませんでした。再度、感謝します! –

関連する問題