次のScala List:
val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))
どうすれば入手することができますか:
List(("a1", "a2", "a3"), ("b1", "b2", "b3"), ("c1", "c2", "c3"))
Zipは2つのリストを結合するためにのみ使用できるため、何らかの方法でメインリストを反復/縮小する必要があると思います。驚くことではありませんが、以下は機能しません:
scala> l reduceLeft ((a, b) => a Zip b)
<console>:6: error: type mismatch;
found : List[(String, String)]
required: List[String]
l reduceLeft ((a, b) => a Zip b)
これを行う方法の提案はありますか?とても簡単な方法が欠けていると思います。
更新: M個の要素を持つN個のリストのリストを取得し、M個のTupleNのリストを作成できるソリューションを探しています。
更新2:判明したように、特定のユースケースでは、タプルのリストよりもリストのリストを使用する方がよいため、カボチャの応答を受け入れています。また、ネイティブメソッドを使用するため、最も簡単です。
任意のサイズのタプルのリストを生成することは不可能だと思いますが、リストのリストを取得することを気にしない場合は、 transpose function がまさに必要なことを行います。
scala> (List(1,2,3),List(4,5,6),List(7,8,9)).zipped.toList
res0: List[(Int, Int, Int)] = List((1,4,7), (2,5,8), (3,6,9))
今後の参考のために。
そのため、このコードはOPのニーズに応えません。これは4年前のスレッドであるだけでなく、タイトルの質問にも答えているため、おそらく誰かが役に立つかもしれません。
3つのコレクションを圧縮するには:
as Zip bs Zip cs map {
case ((a,b), c) => (a,b,c)
}
はい、 Zip で。
transpose
がトリックを行います。可能なアルゴリズムは次のとおりです。
def combineLists[A](ss:List[A]*) = {
val sa = ss.reverse;
(sa.head.map(List(_)) /: sa.tail)(_.Zip(_).map(p=>p._2 :: p._1))
}
例えば:
combineLists(List(1, 2, 3), List(10,20), List(100, 200, 300))
// => List[List[Int]] = List(List(1, 10, 100), List(2, 20, 200))
回答は、入力の最短リストのサイズに切り捨てられます。
combineLists(List(1, 2, 3), List(10,20))
// => List[List[Int]] = List(List(1, 10), List(2, 20))
繰り返しなくてもそれが可能だとは思わない。単純な理由の1つは、要求する関数の戻り値の型を定義できないことです。
たとえば、入力がList(List(1,2)、List(3,4))の場合、戻り値の型はList [Tuple2 [Int]]になります。 3つの要素がある場合、戻り値の型はList [Tuple3 [Int]]などになります。
List [AnyRef]、またはList [Product]を返し、条件ごとに1つのケースを作成できます。
一般的なリスト転置に関しては、これは機能します:
def transpose[T](l: List[List[T]]): List[List[T]] = l match {
case Nil => Nil
case Nil :: _ => Nil
case _ => (l map (_.head)) :: transpose(l map (_.tail))
}
該当するscalaz/cats /(お気に入りの機能ライブラリをここに挿入)のルートに行きたくない場合は、パターンマッチングを使用しますが、(_, _)
構文はネストが少し厄介なので、変更しましょう。
import scala.{Tuple2 => &}
for (i1 & i2 & i3 & i4 <- list1 Zip list2 Zip list3 Zip list4) yield (i1, i2, i3, i4)
&
はここではarbitrary意的な選択であり、Nice infixに見えるものなら何でも行うべきです。ただし、コードのレビュー中に眉を少し上げることがあります。
また、Zip
(例:Future
s)
Scalaは、そのすべての異なるTupleサイズを異なるクラス(Tuple1
、Tuple2
、Tuple3
、Tuple4
、...、Tuple22
)それらはすべてProduct
トレイトから継承しますが、そのトレイトは、同じ関数で返される可能性がある場合、異なるサイズのタプルからのデータ値を実際に使用するのに十分な情報を伝えません。 (そしてscalaのジェネリックはこのケースを処理するのに十分なほど強力ではありません。)
最善の策は、22個すべてのタプルサイズに対してZip関数のオーバーロードを記述することです。コードジェネレーターがおそらくこれに役立ちます。
product-collections は、アリティ22までのa flatZip
操作を持ちます。
scala> List(1,2,3) flatZip Seq("a","b","c") flatZip Vector(1.0,2.0,3.0) flatZip Seq(9,8,7)
res1: com.github.marklister.collections.immutable.CollSeq4[Int,String,Double,Int] =
CollSeq((1,a,1.0,9),
(2,b,2.0,8),
(3,c,3.0,7))
Scalazの場合:
import scalaz.Zip
import scalaz.std.list._
// Zip 3
Zip[List].ap.Tuple3(List("a1", "b1"),
List("a2", "b2"),
List("a3", "b3"))
// Zip 4
Zip[List].ap.Tuple4(List("a1", "b1"),
List("a2", "b2"),
List("a3", "b3"),
List("a4", "b4"))
// Zip 5
Zip[List].ap.Tuple5(List("a1", "b1"),
List("a2", "b2"),
List("a3", "b3"),
List("a4", "b4"),
List("a5", "b5"))
5つ以上の場合:
// Zip 6
Zip[List].ap.apply6(List("a1", "b1"),
List("a2", "b2"),
List("a3", "b3"),
List("a4", "b4"),
List("a5", "b5"),
List("a6", "b6"))((_, _, _, _, _, _))
// Zip 7
Zip[List].ap.apply7(List("a1", "b1"),
List("a2", "b2"),
List("a3", "b3"),
List("a4", "b4"),
List("a5", "b5"),
List("a6", "b6"),
List("a7", "b7"))((_, _, _, _, _, _, _))
...
// Zip 12
Zip[List].ap.apply12(List("a1", "b1"),
List("a2", "b2"),
List("a3", "b3"),
List("a4", "b4"),
List("a5", "b5"),
List("a6", "b6"),
List("a7", "b7"),
List("a8", "b8"),
List("a9", "b9"),
List("a10", "b10"),
List("a11", "b11"),
List("a12", "b12"))((_, _, _, _, _, _, _, _, _, _, _, _))