【问题标题】:Combine multiple sequential entries in Scala/Spark在 Scala/Spark 中组合多个顺序条目
【发布时间】:2018-05-16 15:33:22
【问题描述】:

我有一个用逗号分隔的数字数组,如图所示:

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

我需要这样的输出:

a:{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))

我得到如下输出:

a:{108-108、109-109、110-110、112、114-114、115-115、116-116、118}

我无法弄清楚我哪里出错了。你能帮我纠正这个问题吗? TIA。

【问题讨论】:

  • 请解释导致您预期输出的规则。而且,这与 spark 无关,只是一个 scala 问题
  • @RaphaelRoth 我已经在我的问题中编辑了规则。

标签: scala for-loop if-statement while-loop arraybuffer


【解决方案1】:

这是另一种方式:

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 是在需要时添加的字符串的输出序列。

如果至少有一个元素(ys 可以是一个空列表),它从上一个最大值开始。

第二个是如果它没有跟随,需要重置最小值并将完成的范围添加到输出中。

第三种情况是我们已经到了输入的末尾,只输出结果,而不是再次调用循环。

互联网业力指向任何可以解决如何消除ranges :+ rangeToString(min, max)重复的人!

【讨论】:

    【解决方案2】:

    这里有一个解决方案:

    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

    【讨论】:

    • 感谢@raphael 的解决方案。作为一个初学者,我从来没有想过它可以那么容易地完成。再次感谢!
    猜你喜欢
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2011-12-09
    • 2018-07-06
    • 1970-01-01
    相关资源
    最近更新 更多