Tôi có thể nén nhiều hơn hai danh sách lại với nhau trong Scala không?


93

Đưa ra Danh sách Scala sau:

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

Làm thế nào tôi có thể nhận được:

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

Vì zip chỉ có thể được sử dụng để kết hợp hai Danh sách, tôi nghĩ bạn sẽ cần phải lặp lại / giảm Danh sách chính bằng cách nào đó. Không ngạc nhiên, những điều sau đây không hoạt động:

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)

Bất kỳ đề xuất một cách làm điều này? Tôi nghĩ rằng tôi đang thiếu một cách rất đơn giản để làm điều đó.

Cập nhật: Tôi đang tìm một giải pháp có thể lấy Danh sách N Danh sách với M phần tử mỗi phần và tạo Danh sách M TupleN.

Cập nhật 2: Hóa ra là trường hợp sử dụng cụ thể của tôi tốt hơn nên có một danh sách các danh sách, thay vì một danh sách các bộ giá trị, vì vậy tôi chấp nhận phản hồi của Pumpkin. Nó cũng là đơn giản nhất, vì nó sử dụng một phương thức gốc.


có thể trùng lặp nhiều chuỗi Zip
Suma


@VenkatSudheerReddyAedama Cũng được tôi hỏi, năm ngày sau. ;-)
pr1001

Câu trả lời:


36

Tôi không tin rằng có thể tạo một danh sách các bộ giá trị có kích thước tùy ý, nhưng hàm chuyển vị thực hiện chính xác những gì bạn cần nếu bạn không ngại lấy một danh sách thay thế.


Cảm ơn, nó hoạt động hoàn hảo! Khi tôi đi vào trường hợp sử dụng cụ thể của mình, tôi thấy rằng dù sao thì một danh sách cũng sẽ tốt hơn, vì tôi cần lập bản đồ và giảm bớt các danh sách con khác nhau.
pr1001

2
@JoshCason theo nghĩa hẹp nhất là "nhiều hơn hai", chắc chắn. Ba quả thực nhiều hơn hai. Tôi đã giải thích câu hỏi theo nghĩa rộng hơn là "nhiều hơn hai", nghĩa là nhiều tùy ý. Và trong trường hợp đó, bạn không thể thực hiện những gì câu hỏi muốn, trừ khi bạn đạt được HListnhững điều tương tự.
copumpkin

liên kết trong câu trả lời bị hỏng, liên kết mới là scala-lang.org/api/2.12.1/scala/…
Ramesh

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

Để tham khảo trong tương lai.


32
Điều này rất tốt cho việc nén ba danh sách. Thật xấu hổ vì điều này không hoạt động cho hơn ba danh sách :(
theon

2
Xin lưu ý rằng điều này cần phải ở trong một tuple trước: zippedkhông phải là một chức năng của List.
Nathaniel Ford

6
zippedkhông được chấp nhận trong Scala 2.13. trong 2.13, làml1.lazyZip(l2).lazyZip(l3).toList
Seth Tisue

30

Vì vậy, đoạn mã này sẽ không trả lời nhu cầu của OP, và không chỉ bởi vì đây là một chuỗi bốn năm tuổi, mà nó trả lời câu hỏi tiêu đề và có lẽ ai đó thậm chí có thể thấy nó hữu ích.

Để nén 3 bộ sưu tập:

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

làm 4 bộ sưu tập hình như: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, bạn rút ngắn thànhas zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
keepcoding

Tốt cho danh sách các loại khác nhau.
FP Tự do

11

Có, với zip3 .


2
Cảm ơn, nhưng nó chỉ hoạt động với 3 danh sách. Tôi đang tìm một giải pháp có thể lấy Danh sách N Danh sách với M phần tử mỗi phần tử và tạo Danh sách M TupleN.
pr1001

6

transposethực hiện thủ thuật. Một thuật toán khả thi là:

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

Ví dụ:

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

Câu trả lời được cắt ngắn theo kích thước của danh sách ngắn nhất trong đầu vào.

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

1
Tuy nhiên, câu trả lời này gần như thực hiện được mẹo, tuy nhiên, nó đảo ngược các yếu tố. Bạn có thể đề xuất một phiên bản cải tiến tạo ra đầu ra theo thứ tự mong đợi không? cảm ơn
fracca

Phiên bản sửa đổi vẫn giữ nguyên thứ tự: 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

Xử lý Scala tất cả các kích cỡ khác nhau tuple của nó như các lớp học khác nhau ( Tuple1, Tuple2, Tuple3, Tuple4, ..., Tuple22) trong khi họ làm tất cả những kế thừa từ các Productđặc điểm, đó là đặc điểm không mang đủ thông tin để thực sự sử dụng các giá trị dữ liệu từ các kích thước khác nhau của các bộ nếu tất cả chúng có thể được trả về bởi cùng một hàm. (Và các chỉ số chung của scala cũng không đủ mạnh để xử lý trường hợp này.)

Đặt cược tốt nhất của bạn là viết quá tải hàm zip cho tất cả 22 kích thước Tuple. Một trình tạo mã có thể sẽ giúp bạn điều này.


5

Nếu bạn không muốn đi xuống tuyến ứng dụng scalaz / cat / (chèn lib chức năng yêu thích của bạn tại đây), đối sánh mẫu là cách để thực hiện, mặc dù (_, _)cú pháp hơi khó xử với lồng ghép, vì vậy hãy thay đổi nó:

import scala.{Tuple2 => &}

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

Đây &là một sự lựa chọn tùy ý ở đây, bất cứ thứ gì có infix trông đẹp mắt đều nên làm điều đó. Tuy nhiên, bạn có thể sẽ phải nhíu mày trong khi xem xét mã.

Nó cũng sẽ hoạt động với bất kỳ thứ gì bạn có thể zip(ví dụ: Futures)


5

Tôi không tin điều đó có thể xảy ra nếu không lặp lại. Vì một lý do đơn giản: bạn không thể xác định kiểu trả về của hàm mà bạn đang yêu cầu.

Ví dụ, nếu đầu vào của bạn là List(List(1,2), List(3,4)), thì kiểu trả về sẽ là List[Tuple2[Int]]. Nếu nó có ba phần tử, kiểu trả về sẽ là List[Tuple3[Int]], v.v.

Bạn có thể quay lại List[AnyRef], hoặc thậm chí List[Product], và sau đó tạo ra một loạt các trường hợp, một trường hợp cho mỗi điều kiện.

Đối với chuyển vị Danh sách chung, điều này hoạt động:

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

Điều này sẽ không hoạt động cho các danh sách có kích thước tùy ý. Ví dụ: chuyển vị (Danh sách (Danh sách ("a", "b"), Danh sách ("c")))
Venkat Sudheer Reddy Aedama

1
@VenkatSudheerReddyAedama Việc chuyển vị của ma trận không đầy đủ không có ý nghĩa đối với tôi. Để lấy ví dụ của bạn, nếu cphù hợp với ahoặc với b? Và làm thế nào bạn sẽ cho thấy nó phù hợp với cái khác?
Daniel C. Sobral

Đã đồng ý. Đó là một ma trận không đầy đủ. Tôi đang tìm kiếm thứ gì đó dọc theo dòng zipAll. Giả sử trong trường hợp của tôi, clà phù hợp với a(tức là trong dòng với chỉ mục)?
Venkat Sudheer Reddy Aedama

2

sản phẩm-bộ sưu tậpflatZiphoạt động cho đến hiếm 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

Với 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"))

Đối với hơn 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"))((_, _, _, _, _, _, _, _, _, _, _, _))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.