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.
scala
functional-programming
list
zip
pr1001
sumber
sumber
Jawaban:
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.
sumber
HList
s dan sejenisnya.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.
sumber
zipped
bukan merupakan fungsi dariList
.zipped
tidak digunakan lagi di Scala 2.13. di 2.13, lakukanl1.lazyZip(l2).lazyZip(l3).toList
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) }
sumber
as zip bs zip cs zip ds map { case ((a,b),c)} map {case ((a,b),c,d)=>(a,b,c,d)}
as zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
Ya, dengan zip3 .
sumber
transpose
melakukan 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))
sumber
def combineLists[A](ss:List[A]*) = { val sa = ss.reverse; (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1)) }
Scala memperlakukan semua ukuran tuple yang berbeda sebagai kelas yang berbeda (
Tuple1
,Tuple2
,Tuple3
,Tuple4
, ...,Tuple22
) sementara mereka melakukan semua mewarisi dariProduct
sifat, 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.
sumber
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
(misFuture
.)sumber
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 adalahList[Tuple2[Int]]
. Jika memiliki tiga elemen, tipe kembaliannya adalahList[Tuple3[Int]]
, dan seterusnya.Anda dapat mengembalikan
List[AnyRef]
, atau bahkanList[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)) }
sumber
c
sejalan dengana
atau denganb
? Dan bagaimana Anda akan menyatakannya sejalan dengan yang lain?c
sejalan dengana
(yaitu, sejalan dengan indeks)?produk-koleksi memiliki
flatZip
operasi 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))
sumber
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"))((_, _, _, _, _, _, _, _, _, _, _, _))
sumber