合并 Scala/Spark 中的多个连续条目
Combine multiple sequential entries in Scala/Spark
我有一个用逗号分隔的数字数组,如下所示:
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.
这里有一个解决方案:
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)
}
这个解决方案部分使用了这个问题的代码:
这是另一种方式:
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)
基本上这是一个尾递归函数——也就是说,你把你的 "variables" 作为输入,然后它在每个循环中用更新的 "variables" 调用自己。所以这里 xs
是你的数组,min
和 max
是用于跟踪到目前为止的最低和最高数字的整数,ranges
是字符串的输出序列在需要时添加到。
第一个模式(y
是第一个元素,ys
是序列的其余部分 - 因为这就是 +:
提取器的工作方式)如果至少有一个元素(ys
可以是一个空列表)并且它是从前一个最大值开始的。
第二种是如果没有继续,需要重新设置最小值,把完成的范围加到输出中。
第三种情况是我们已经到了输入的末尾,只输出结果,而不是再次调用循环。
互联网业力指向任何人谁可以找出如何消除重复 ranges :+ rangeToString(min, max)
!
我有一个用逗号分隔的数字数组,如下所示:
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.
这里有一个解决方案:
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)
}
这个解决方案部分使用了这个问题的代码:
这是另一种方式:
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)
基本上这是一个尾递归函数——也就是说,你把你的 "variables" 作为输入,然后它在每个循环中用更新的 "variables" 调用自己。所以这里 xs
是你的数组,min
和 max
是用于跟踪到目前为止的最低和最高数字的整数,ranges
是字符串的输出序列在需要时添加到。
第一个模式(y
是第一个元素,ys
是序列的其余部分 - 因为这就是 +:
提取器的工作方式)如果至少有一个元素(ys
可以是一个空列表)并且它是从前一个最大值开始的。
第二种是如果没有继续,需要重新设置最小值,把完成的范围加到输出中。
第三种情况是我们已经到了输入的末尾,只输出结果,而不是再次调用循环。
互联网业力指向任何人谁可以找出如何消除重复 ranges :+ rangeToString(min, max)
!