14

次の方法で複数のリストに参加する方法を探しています。

ListA a b c
ListB 1 2 3 4
ListC + # * § %
..
..
..

Resulting List: a 1 + b 2 # c 3 * 4 § %

言い換えれば、最初のリストから始まる順番の要素が、結果のリストに結合されます。長さの異なる任意の量の入力リストが存在する可能性があります。

zip のバリアント、スライディング イテレータを使用して複数のアプローチを使用しましたが、どれも機能せず、特にさまざまなリストの長さを処理しました。scalaにはエレガントな方法が必要です;)

4

7 に答える 7

20
val lists = List(ListA, ListB, ListC)

lists.flatMap(_.zipWithIndex).sortBy(_._2).map(_._1)

それはかなり自明です。各値をそれぞれのリストの位置で圧縮し、インデックスで並べ替えてから、値を引き出します。

于 2013-09-30T17:15:23.080 に答える
5

これが私がそれを行う方法です:

class ListTests extends FunSuite {
  test("The three lists from his example") {
    val l1 = List("a", "b", "c")
    val l2 = List(1, 2, 3, 4)
    val l3 = List("+", "#", "*", "§", "%")

    // All lists together
    val l = List(l1, l2, l3)

    // Max length of a list (to pad the shorter ones)
    val maxLen = l.map(_.size).max

    // Wrap the elements in Option and pad with None
    val padded = l.map { list => list.map(Some(_)) ++ Stream.continually(None).take(maxLen - list.size) }

    // Transpose 
    val trans = padded.transpose

    // Flatten the lists then flatten the options
    val result = trans.flatten.flatten

    // Viola 
    assert(List("a", 1, "+", "b", 2, "#", "c", 3, "*", 4, "§", "%") === result)
  }
}
于 2013-09-30T15:09:49.010 に答える
1

ここに小さな再帰的な解決策があります。

def flatList(lists: List[List[Any]]) = {
  def loop(output: List[Any], xss: List[List[Any]]): List[Any] = (xss collect { case x :: xs => x }) match {
    case Nil => output
    case heads => loop(output ::: heads, xss.collect({ case x :: xs => xs })) 
  }
  loop(List[Any](), lists)
}

そして、これは、潜在的に無限の長さのシーケンスの任意のシーケンスに対処できる単純なストリーム アプローチです。

def flatSeqs[A](ssa: Seq[Seq[A]]): Stream[A] = {
  def seqs(xss: Seq[Seq[A]]): Stream[Seq[A]] = xss collect { case xs if !xs.isEmpty => xs } match {
    case Nil => Stream.empty
    case heads => heads #:: seqs(xss collect { case xs if !xs.isEmpty => xs.tail })
  }
  seqs(ssa).flatten
}
于 2013-09-30T16:12:55.230 に答える
1

効率が最優先される場合の必須の解決策は次のとおりです。

def combine[T](xss: List[List[T]]): List[T] = {
  val b = List.newBuilder[T]
  var its = xss.map(_.iterator)
  while (!its.isEmpty) {
    its = its.filter(_.hasNext)
    its.foreach(b += _.next)
  }
  b.result
}
于 2013-09-30T17:23:22.563 に答える
1

padToここでは、 、transpose、およびflattenを効果的に使用できます。

lists.map(_.map(Some(_)).padTo(lists.map(_.length).max, None)).transpose.flatten.flatten
于 2015-04-01T03:05:09.543 に答える
0

以下は短いものですが、非常に効率的ではありません。

def heads[A](xss: List[List[A]]) = xss.map(_.splitAt(1)).unzip
def interleave[A](xss: List[List[A]]) = Iterator.
  iterate(heads(xss)){ case (_, tails) => heads(tails) }.
  map(_._1.flatten).
  takeWhile(! _.isEmpty).
  flatten.toList
于 2013-09-30T17:15:20.487 に答える