这是一个非常简单的解决方案:
def splitAlt[T](s: Seq[T]): (Seq[T], Seq[T]) = {
val (fsts, snds) = s.zipWithIndex.partition { case (x, i) => i % 2 == 0 }
(fsts.map(_._1), snds.map(_._1))
}
splitAlt("") // -> (Seq(), Seq())
splitAlt("a") // -> (Seq(a), Seq())
splitAlt("ab") // -> (Seq(a), Seq(b))
splitAlt("abc") // -> (Seq(a, c), Seq(b))
splitAlt("abcd") // -> (Seq(a, c), Seq(b, d))
splitAlt("abcde") // -> (Seq(a, c, e), Seq(b, d))
我声称它很优雅,因为:
- 不抛出异常,只返回空序列;
- 它适用于任何类型的序列,而不仅仅是字符;
- 它适用于任何长度的序列;
- 它只遍历序列一次。
更新:这是对任意数量组的概括:
def splitGen[T](xs: Seq[T], n: Int): Seq[Seq[T]] = {
val groups =
xs.zipWithIndex
.groupBy { case (x, i) => i % n }
.mapValues { vs => vs.map(_._1) }
0 until n map groups
}
splitGen("abcdefg", 1) // -> Seq(Seq(a, b, c, d, e, f, g))
splitGen("abcdefg", 2) // -> Seq(Seq(a, c, e, g), Seq(b, d, f))
splitGen("abcdefg", 3) // -> Seq(Seq(a, d, g), Seq(b, e), Seq(c, f))
splitGen("abcdefg", 4) // -> Seq(Seq(a, e), Seq(b, f), Seq(c, g), Seq(d))
splitGen("abcdefg", 5) // -> Seq(Seq(a, f), Seq(b, g), Seq(c), Seq(d), Seq(e))
你可以泛化grouped+transpose的解决方案,将原始序列填充到恰到好处的长度,然后取消填充结果,但这需要你处理一些特殊情况:
def splitGen[T](xs: Seq[T], n: Int): Seq[Seq[T]] = {
/* Pad */
val paddedLength: Int = math.ceil(xs.length / n.toDouble).toInt * n
val padded: Seq[T] =
if (xs.isEmpty) xs
else xs.padTo(paddedLength, xs.head)
/* Transpose */
val transposed = padded.grouped(n).toList.transpose
/* Unpad */
if (paddedLength == xs.length) transposed
else transposed.zipWithIndex.map { case (row, i) =>
if (i < xs.length % n) row
else row.init
}
}