Scalaで3つ以上のリストを一緒に圧縮できますか?


92

次のScalaリストがあるとします。

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タプルNのリストを作成できるソリューションを探しています。

更新2:結局のところ、私の特定のユースケースでは、タプルのリストではなくリストのリストを使用する方が良いため、カボチャの応答を受け入れます。また、ネイティブメソッドを使用するため、最も単純です。




@VenkatSudheerReddyAedama 5日後、私からも尋ねられました。;-)
pr1001 2015

回答:


36

任意のサイズのタプルのリストを生成することは可能だとは思いませんが、代わりにリストのリストを取得してもかまわない場合は、転置関数がまさに必要なことを行います。


ありがとう、それは完璧に機能します!特定のユースケースに入ると、さまざまなサブリストをマップして削減する必要があるため、リストのリストがとにかく優れていることがわかります。
pr1001 2009年

2
「2つ以上」という最も狭い意味での@JoshCason。確かに3つは2つ以上です。私は「2つ以上」という広い意味で質問を解釈しました。そしてその場合、HListsなどに到達しない限り、質問が望むことを実行することはできません。
コパンプキン2016年

答えでリンクが壊れている、新しいリンクがあるscala-lang.org/api/2.12.1/scala/...
ラメMaharjan

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

今後の参考のために。


32
これは、3つのリストを圧縮するのに最適です。これが3つを超えるリストでは機能しないのは残念です:(
theon

2
これは最初にタプルである必要があることに注意してください:はのzipped関数ではありませんList
Nathaniel Ford

6
zippedScala 2.13では非推奨です。2.13で、行うl1.lazyZip(l2).lazyZip(l3).toList
Seth Tisue

30

したがって、このコードはOPのニーズに対応しません。これは4年前のスレッドであるためだけでなく、タイトルの質問にも対応しており、おそらく誰かが役立つかもしれません。

3つのコレクションを圧縮するには:

as zip bs zip cs map { 
  case ((a,b), c) => (a,b,c)
}

4つのコレクションを行うには、次のようになりますas zip bs zip cs zip ds map { case ((a,b),c)} map {case ((a,b),c,d)=>(a,b,c,d)}
ジェームズ・トービン

1
@ JamesTobin、u短縮as zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
2017年

さまざまなタイプのリストに適しています。
FP Freely

11

はい、zip3を使用します。


2
おかげで、それは3つのリストでのみ機能します。それぞれM要素のNリストのリストを取得し、MタプルNのリストを作成できるソリューションを探しています。
pr1001 2009年

6

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
この答えはほとんどトリックを行いますが、要素を逆にします。期待される順序で出力を生成する改良バージョンを提案できますか?ありがとう
fracca

順序を保持する修正バージョン: def combineLists[A](ss:List[A]*) = { val sa = ss.reverse; (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1)) }
rogermenezes

5

すべての異なるクラスとしての異なるタプルサイズのScalaの扱い(Tuple1Tuple2Tuple3Tuple4、...、 Tuple22)彼らはからすべての継承を行いながら、Product形質は、実際のタプルの異なるサイズからデータ値を使用するのに十分な情報を有していないことを、トレイトそれらがすべて同じ関数によって返される場合。(そして、scalaのジェネリックは、このケースを処理するのに十分強力ではありません。)

あなたの最善の策は、22のすべてのタプルサイズに対してzip関数のオーバーロードを記述することです。コードジェネレーターはおそらくこれに役立ちます。


5

アプリケーションのscalaz / cats /(ここにお気に入りの機能ライブラリを挿入する)ルートを使いたくない場合は、パターンマッチングが適してい(_, _)ますが、構文はネストが少し厄介なので、変更してみましょう。

import scala.{Tuple2 => &}

for (i1 & i2 & i3 & i4 <- list1 zip list2 zip list3 zip list4) yield (i1, i2, i3, i4)

&は任意の選択ですが、見栄えの良いinfixであれば何でも実行できます。ただし、コードのレビュー中に眉毛が数本発生する可能性があります。

また、できることなら何でも機能するはずですzip(例:Futures)


5

私はそれが反復的でなくて可能であるとは思わない。単純な理由の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))
}

これは、任意のサイズのリストでは機能しません。例:transpose(List(List( "a"、 "b")、List( "c")))
Venkat Sudheer Reddy Aedama

1
@VenkatSudheerReddyAedama不完全な行列の転置は私には意味がありません。あなたの例を取るために、またはcに沿っているa場合はb?そして、あなたはそれが他と一致していることをどのように表現しますか?
ダニエルC.ソブラル2015年

同意した。これは不完全なマトリックスです。私はzipAllに沿って何かを探していました。私の場合cは、と一致していますa(つまり、インデックスと一致しています)?
Venkat Sudheer Reddy Aedama 2015

2

product-collectionsには、flatZiparity 22までの操作があります。

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

0

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"))((_, _, _, _, _, _, _, _, _, _, _, _))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.