将一个序列分成两个交替的序列

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

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

我发现了一个优雅的solution和我想使用的groupedtranspose
不幸的是,它仅在输入序列具有偶数大小的情况下起作用。
您将如何修改该解决方案以适用于任何大小的输入?

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

hbfym 回答:将一个序列分成两个交替的序列

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

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,Seq(b,d))
splitAlt("abcde") // -> (Seq(a,c,e),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,d,e,f,g))
splitGen("abcdefg",2)  // -> Seq(Seq(a,g),f))
splitGen("abcdefg",3)  // -> Seq(Seq(a,Seq(c,4)  // -> Seq(Seq(a,f),Seq(d))
splitGen("abcdefg",5)  // -> Seq(Seq(a,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
  }

}

,

这是一种基于grouped + transpose解决方案的方法。

def splitAlt[T](s: Seq[T]) = {
    s.grouped(2).toList.map(p => Seq(p.headOption,p.tail.headOption)).transpose.map(_.flatten)
}

基本上,它将List[T]返回的内部grouped转换为具有两个元素的List[Option[T]],因为transpose要求所有集合的大小都相等。

请注意,这将返回嵌套列表,而不是一对列表。如果要将结果转换为元组,我们需要特别注意少于2个元素的情况,因此为了“优雅”,我将其保留为这样。

本文链接:https://www.f2er.com/3058302.html

大家都在问