Bisakah saya membuat lebih dari dua daftar menjadi satu di Scala?

94

Diberikan Daftar Scala berikut:

val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))

Bagaimana saya bisa mendapatkan:

List(("a1", "a2", "a3"), ("b1", "b2", "b3"), ("c1", "c2", "c3"))

Karena zip hanya dapat digunakan untuk menggabungkan dua List, saya rasa Anda perlu mengulang / mengurangi List utama. Tidak mengherankan, hal berikut ini tidak berhasil:

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)

Ada saran bagaimana melakukan ini? Saya pikir saya kehilangan cara yang sangat sederhana untuk melakukannya.

Pembaruan: Saya mencari solusi yang dapat mengambil Daftar N Daftar dengan elemen M masing-masing dan membuat Daftar M TupleNs.

Pembaruan 2: Ternyata lebih baik untuk kasus penggunaan khusus saya memiliki daftar daftar, daripada daftar tupel, jadi saya menerima tanggapan labu. Ini juga yang paling sederhana, karena menggunakan metode asli.

pr1001
sumber
kemungkinan duplikat dari beberapa urutan Zip
Suma
Patut diperhatikan: stackoverflow.com/questions/1683312/…
Sudheer Aedama
@VenkatSudheerReddyAedama Juga ditanyakan oleh saya, lima hari kemudian. ;-)
pr1001

Jawaban:

36

Saya tidak percaya itu mungkin untuk menghasilkan daftar tupel dengan ukuran sewenang-wenang, tetapi fungsi transpose melakukan persis apa yang Anda butuhkan jika Anda tidak keberatan mendapatkan daftar daftar sebagai gantinya.

copumpkin
sumber
Terima kasih, itu berfungsi dengan sempurna! Saat saya membahas kasus penggunaan khusus saya, saya melihat bahwa daftar daftar akan lebih baik, karena saya perlu memetakan dan mengurangi berbagai sub-daftar.
pr1001
2
@JoshCason dalam arti sempit "lebih dari dua", tentu. Tiga memang lebih dari dua. Saya menafsirkan pertanyaan itu dalam arti yang lebih luas "lebih dari dua", yang berarti banyak secara sewenang-wenang. Dan dalam hal ini, tidak mungkin melakukan apa yang diinginkan pertanyaan, kecuali Anda meraih HLists dan sejenisnya.
copumpkin
link di jawaban rusak, link baru scala-lang.org/api/2.12.1/scala/…
Ramesh Maharjan
216
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))

Untuk referensi di masa mendatang.

Xorlev
sumber
32
Ini bagus untuk membuat zip tiga daftar. Sayang sekali ini tidak berhasil untuk lebih dari tiga daftar :(
theon
2
Perhatikan bahwa ini harus di tupel terlebih dahulu: zippedbukan merupakan fungsi dari List.
Nathaniel Ford
6
zippedtidak digunakan lagi di Scala 2.13. di 2.13, lakukanl1.lazyZip(l2).lazyZip(l3).toList
Seth Tisue
30

Jadi potongan kode ini tidak akan menjawab kebutuhan OP, dan bukan hanya karena ini adalah utas berumur empat tahun, tetapi juga menjawab pertanyaan judul, dan mungkin seseorang bahkan mungkin menganggapnya berguna.

Untuk zip 3 koleksi:

as zip bs zip cs map { 
  case ((a,b), c) => (a,b,c)
}
Bijou Trouvaille
sumber
untuk melakukan 4 koleksi seperti:as zip bs zip cs zip ds map { case ((a,b),c)} map {case ((a,b),c,d)=>(a,b,c,d)}
James Tobin
1
@JamesTobin, u persingkat menjadias zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
keepscoding
Bagus untuk daftar jenis yang berbeda-beda.
FP Freely
11

Ya, dengan zip3 .

Harold L.
sumber
2
Terima kasih, tetapi ini hanya berfungsi dengan 3 daftar. Saya mencari solusi yang dapat mengambil Daftar N Daftar dengan masing-masing elemen M dan membuat Daftar M TupleNs.
pr1001
6

transposemelakukan triknya. Algoritme yang mungkin adalah:

def combineLists[A](ss:List[A]*) = {
    val sa = ss.reverse;
    (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1))
}

Sebagai contoh:

combineLists(List(1, 2, 3), List(10,20), List(100, 200, 300))
// => List[List[Int]] = List(List(1, 10, 100), List(2, 20, 200))

Jawabannya dipotong menjadi ukuran daftar terpendek di input.

combineLists(List(1, 2, 3), List(10,20))
// => List[List[Int]] = List(List(1, 10), List(2, 20))
WP McNeill
sumber
1
jawaban ini hampir berhasil, namun membalikkan elemennya. Dapatkah Anda menyarankan versi perbaikan yang menghasilkan keluaran dalam urutan yang diharapkan? terima kasih
fracca
Versi modifikasi yang mempertahankan urutan: 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 memperlakukan semua ukuran tuple yang berbeda sebagai kelas yang berbeda ( Tuple1, Tuple2, Tuple3, Tuple4, ..., Tuple22) sementara mereka melakukan semua mewarisi dari Productsifat, yang sifat tidak membawa informasi yang cukup untuk benar-benar menggunakan nilai data dari ukuran yang berbeda dari tupel jika semuanya bisa dikembalikan dengan fungsi yang sama. (Dan obat generik scala tidak cukup kuat untuk menangani kasus ini juga.)

Taruhan terbaik Anda adalah menulis kelebihan fungsi zip untuk semua 22 ukuran Tuple. Generator kode mungkin akan membantu Anda dalam hal ini.

Ken Bloom
sumber
5

Jika Anda tidak ingin menggunakan rute aplikatif scalaz / kucing / (masukkan lib fungsional favorit Anda di sini), pencocokan pola adalah cara yang harus dilakukan, meskipun (_, _)sintaksnya agak canggung dengan penyarangan, jadi mari kita ubah:

import scala.{Tuple2 => &}

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

Ini &adalah pilihan yang sewenang-wenang di sini, apa pun yang terlihat bagus harus dilakukan. Namun, Anda mungkin akan mendapatkan sedikit alis selama peninjauan kode.

Ini juga harus bekerja dengan apa pun yang Anda bisa zip(mis Future.)

L4Z
sumber
5

Saya tidak percaya itu mungkin tanpa diulang-ulang. Untuk satu alasan sederhana: Anda tidak dapat menentukan tipe kembalian dari fungsi yang Anda minta.

Misalnya, jika masukan Anda adalah List(List(1,2), List(3,4)), maka jenis kembaliannya adalah List[Tuple2[Int]]. Jika memiliki tiga elemen, tipe kembaliannya adalah List[Tuple3[Int]], dan seterusnya.

Anda dapat mengembalikan List[AnyRef], atau bahkan List[Product], dan kemudian membuat banyak kasus, satu untuk setiap kondisi.

Sedangkan untuk transposisi Daftar umum, ini berfungsi:

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))
}
Daniel C. Sobral
sumber
Ini tidak akan berfungsi untuk daftar berukuran sewenang-wenang. Misalnya: transpos (Daftar (Daftar ("a", "b"), Daftar ("c")))
Sudheer Aedama
1
@VenkatSudheerReddyAedama Transposisi matriks yang tidak lengkap tidak masuk akal bagi saya. Ambil contoh Anda, apakah csejalan dengan aatau dengan b? Dan bagaimana Anda akan menyatakannya sejalan dengan yang lain?
Daniel C. Sobral
Sepakat. Itu matriks yang tidak lengkap. Saya mencari sesuatu yang mirip dengan zipAll. Katakanlah dalam kasus saya, csejalan dengan a(yaitu, sejalan dengan indeks)?
Sudheer Aedama
2

produk-koleksi memiliki flatZipoperasi hingga arity 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))
Tandai Lister
sumber
0

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

Selama lebih dari 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"))((_, _, _, _, _, _, _, _, _, _, _, _))
ZhekaKozlov
sumber