将一个序列分成两个交替的序列 [英] Split a sequence into two alternating sequences

查看:74
本文介绍了将一个序列分成两个交替的序列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将大小> 2的序列分成这样的交替序列:

I would like to split a sequence of size > 2 into alternating sequences like this:

def splitAlt(s: Seq[Char]): (Seq[Char], Seq[Char]) = ???

splitAlt(Nil)  // raise an exception
splitAlt("a")  // raise an exception  
splitAlt("ab") // (Seq('a'), Seq('b'))
splitAlt("abc") // (Seq('a', 'c'), Seq('b'))

我找到了一个优雅的解决方案,其中 grouped transpose 我想使用.
不幸的是,它仅在输入序列具有偶数大小的情况下才起作用.
您将如何修改该解决方案以适用于任何大小的输入?

I found an elegant solution with grouped and transpose I'd like to use.
Unfortunately it works only i fthe input sequence has even size.
How would you modify that solution to work for input of any size ?

您有更优雅的解决方案吗?

Do you have a more elegant solution ?

推荐答案

这是一个非常简单的解决方案:

This is a very straightforward solution:

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))

我声称它很优雅,因为:

I claim it's elegant because:

  • 它不会引发异常,它只会返回空序列;
  • 它适用于任何类型的序列,而不仅仅是字符;
  • 它适用于任何长度的序列;
  • 它仅遍历一次序列.

更新:这是任意数量的组的概括:

Update: this is a generalization for an arbitrary number of groups:

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 解决方案,但这需要您注意一些特殊情况:

You can generalize the grouped+transpose solution by padding the original sequence for the length to be just right and then unpadding the result, but it requires you to take care of some special cases:

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
  }

}

这篇关于将一个序列分成两个交替的序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆