我正在尝试合并两个序列,以便它们保持排序状态。以下是我写的代码:
val seq1 = Seq(1,3,5,7,9)
val seq2 = Seq(2,4,6,8)
var arr = Seq[Int]()
for(b <- seq2)
{
for(a <- seq1)
{
if(a < b)
arr = arr :+ a
else
{
arr = arr :+ b;break;
}
}
}
println(arr)
我需要的输出是:
Seq(1,2,3,4,5,6,7,8,9)
但似乎break在Scala中不起作用。我对这门语言比较陌生。执行此操作的最佳方法是什么?
答案 0 :(得分:21)
最简单的方法可能是:
(seq1 ++ seq2).sorted
如果seq1
和seq2
包含其他类型,则必须为该类型提供Ordering
;或者,使用sortBy
方法,将每个元素映射到可以隐式找到Ordering
的另一种类型的元素:
(seq1 ++ seq2).sortBy(_.toDate)
答案 1 :(得分:6)
以下内容也适用于非交错序列:
def mergeSorted[E: Ordering](x: Seq[E], y: Seq[E]): Seq[E] = {
val ordering = implicitly[Ordering[E]]
@tailrec
def rec(x: Seq[E], y: Seq[E], acc: Seq[E]): Seq[E] = {
(x, y) match {
case (Nil, Nil) => acc
case (_, Nil) => acc ++ x
case (Nil, _) => acc ++ y
case (xh :: xt, yh :: yt) =>
if (ordering.lteq(xh, yh))
rec(xt, y, acc :+ xh)
else
rec(x, yt, acc :+ yh)
}
}
rec(x, y, Seq())
}
请注意,出于性能原因,您可能会使用Builders(vs.:+,+ :, reverse)。
答案 2 :(得分:5)
我很高兴找到@ CaringDev的解决方案并使其适应使用Builder
:
def mergeSortedBuilder[E: Ordering](x: Seq[E], y: Seq[E])(implicit ordering: Ordering[E]): Seq[E] = {
@tailrec
def rec(x: Seq[E], y: Seq[E], acc: Builder[E, Seq[E]]): Builder[E, Seq[E]] = {
(x, y) match {
case (Nil, Nil) => acc
case (_, Nil) => acc ++= x
case (Nil, _) => acc ++= y
case (xh :: xt, yh :: yt) =>
if (ordering.lteq(xh, yh))
rec(xt, y, acc += xh)
else
rec(x, yt, acc += yh)
}
}
rec(x, y, Seq.newBuilder).result
}
答案 3 :(得分:1)
要在保持各自顺序的同时交错两个序列,您可以使用:
scala> seq1.zip(seq2).flatMap(pair => Seq(pair._1,pair._2))
res1: Seq[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
但是,请注意,对于长度不等的序列,这会丢失较长序列的额外元素。这可以通过更多的努力进行整理(找到两个列表中较长的一个,并添加longer.drop(shorter.length)
)。
答案 4 :(得分:0)
如果要按顺序交错任意数量的序列,可以使用类似的
implicit class Interleave[T](input: Seq[Seq[T]]) {
def interleave: Seq[T] = {
input.foldLeft(Seq[Seq[T]]()) { (acc, cur) =>
if (acc.isEmpty) cur.map { m => Seq(m) }
else (acc zip cur).map { case (sequence, m) =>
sequence :+ m
}
}.flatten.toVector
}
}
可能有可能改善此性能,尤其是在toVector
主要用于将流转换为渴望的内容的情况下。
用法看起来像
Seq(Seq(1,2), Seq(2,3), Seq(3,4)).interleave should be(Seq(1,2,3,2,3,4))