ฉันสามารถซิปมากกว่าสองรายการพร้อมกันใน Scala ได้หรือไม่


94

รับรายการ 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 สามารถใช้เพื่อรวมสองรายการเท่านั้นฉันคิดว่าคุณจะต้องวนซ้ำ / ลดรายการหลักอย่างใด ไม่น่าแปลกใจที่สิ่งต่อไปนี้ใช้ไม่ได้:

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)

มีข้อเสนอแนะวิธีการทำอย่างไร ฉันคิดว่าฉันกำลังพลาดวิธีง่ายๆในการทำ

อัปเดต:ฉันกำลังมองหาโซลูชันที่สามารถใช้ List of N Lists ที่มีองค์ประกอบ M และสร้าง List of M TupleNs

อัปเดต 2:ตามที่ปรากฏจะดีกว่าสำหรับกรณีการใช้งานเฉพาะของฉันที่จะมีรายการรายการแทนที่จะเป็นรายการสิ่งที่เพิ่มขึ้นดังนั้นฉันจึงยอมรับคำตอบของฟักทอง นอกจากนี้ยังเป็นวิธีที่ง่ายที่สุดเนื่องจากใช้วิธีดั้งเดิม


เป็นไปได้ที่จะซ้ำกันของZip หลายลำดับ
Suma

คุ้มกว่าแน่นอน: stackoverflow.com/questions/1683312/…
Sudheer Aedama

@VenkatSudheerReddyAedama ถามฉันด้วยห้าวันต่อมา ;-)
pr1001

คำตอบ:


36

ฉันไม่เชื่อว่าเป็นไปได้ที่จะสร้างรายการสิ่งที่มีขนาดตามอำเภอใจ แต่ฟังก์ชันการเปลี่ยนจะทำตามที่คุณต้องการหากคุณไม่คิดจะรับรายการแทน


ขอบคุณที่ทำงานได้อย่างสมบูรณ์แบบ! เมื่อฉันเข้าสู่กรณีการใช้งานที่เฉพาะเจาะจงของฉันฉันเห็นว่ารายการจะดีกว่าอยู่แล้วเนื่องจากฉันต้องแมปและลดรายการย่อยต่างๆ
pr1001

2
@JoshCason ในความหมายที่แคบที่สุดของ "มากกว่าสอง" นั่นเอง สามย่อมมากกว่าสอง ฉันตีความคำถามในความหมายที่กว้างกว่าของ "มากกว่าสอง" ซึ่งหมายถึงจำนวนมากโดยพลการ และในกรณีนี้จะเป็นไปไม่ได้ที่จะทำในสิ่งที่คำถามต้องการเว้นแต่คุณจะไปถึงHLists และชอบ
copumpkin

ลิงค์ในคำตอบเสียลิงค์ใหม่คือscala-lang.org/api/2.12.1/scala/…
Ramesh

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

สำหรับการอ้างอิงในอนาคต.


32
เหมาะสำหรับการซิปสามรายการ ความอัปยศนี้ไม่ได้ทำงานมานานกว่าสามรายการ :(
Theon

2
โปรดทราบว่าสิ่งนี้ต้องอยู่ในทูเพิลก่อน: zippedไม่ใช่หน้าที่ของList.
Nathaniel Ford

6
zippedเลิกใช้แล้วใน Scala 2.13 ใน 2.13l1.lazyZip(l2).lazyZip(l3).toList
Seth Tisue

30

ดังนั้นโค้ดชิ้นนี้จะไม่ตอบโจทย์ความต้องการของ OP และไม่เพียงเพราะนี่เป็นเธรดเก่าสี่ปี แต่มันตอบคำถามชื่อเรื่องและบางทีบางคนอาจพบว่ามีประโยชน์

ในการซิป 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)}
James Tobin

1
@JamesTobin คุณย่อเป็นas zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
keepscoding

เหมาะสำหรับรายการประเภทต่างๆ
FP อิสระ

11

ใช่กับzip3 .


2
ขอบคุณ แต่ใช้ได้กับ 3 รายการเท่านั้น ฉันกำลังมองหาวิธีแก้ปัญหาที่สามารถใช้ List of N Lists ที่มีองค์ประกอบ M และสร้าง List of M TupleNs
pr1001

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 ทุกขนาด tuple ของมันแตกต่างกันเป็นชั้นเรียนที่แตกต่างกัน ( Tuple1, Tuple2, Tuple3, Tuple4, ... Tuple22) ในขณะที่พวกเขาทำสืบทอดทั้งหมดออกจากProductลักษณะว่าลักษณะที่ไม่ได้พกข้อมูลเพียงพอที่จะใช้งานจริงค่าข้อมูลจากขนาดที่แตกต่างกันของ tuples ถ้าพวกเขาสามารถส่งคืนทั้งหมดโดยฟังก์ชันเดียวกัน (และข้อมูลทั่วไปของสกาล่าก็ไม่ได้มีประสิทธิภาพเพียงพอที่จะจัดการกับกรณีนี้เช่นกัน

ทางออกที่ดีที่สุดของคุณคือเขียนฟังก์ชัน zip ที่มากเกินไปสำหรับขนาด 22 Tuple ทั้งหมด เครื่องสร้างโค้ดอาจช่วยคุณได้


5

หากคุณไม่ต้องการใช้เส้นทาง scalaz / cats / (แทรกฟังก์ชัน lib ที่คุณชื่นชอบที่นี่) การจับคู่รูปแบบเป็นวิธีที่จะไปแม้ว่า(_, _)ไวยากรณ์จะค่อนข้างอึดอัดกับการซ้อนดังนั้นเรามาเปลี่ยนกัน:

import scala.{Tuple2 => &}

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

&เป็นทางเลือกโดยพลนี่อะไรที่ดูดีมัดควรจะทำมัน คุณอาจจะเลิกคิ้วขึ้นเล็กน้อยในระหว่างการตรวจสอบโค้ด

นอกจากนี้ยังควรทำงานร่วมกับทุกสิ่งที่คุณสามารถทำได้zip(เช่นFuture)


5

ฉันไม่เชื่อว่าจะเป็นไปได้โดยไม่ต้องซ้ำซาก ด้วยเหตุผลง่ายๆเพียงข้อเดียว: คุณไม่สามารถกำหนดประเภทการส่งคืนของฟังก์ชันที่คุณต้องการได้

ตัวอย่างเช่นถ้าใส่ของคุณแล้วพิมพ์กลับจะเป็นList(List(1,2), List(3,4)) List[Tuple2[Int]]หากมีสามองค์ประกอบประเภทการส่งคืนจะเป็นList[Tuple3[Int]]และอื่น ๆ

คุณสามารถส่งคืนList[AnyRef]หรือแม้กระทั่งList[Product]แล้วสร้างหลายกรณีสำหรับแต่ละเงื่อนไข

สำหรับการขนย้ายรายการทั่วไปการทำงานนี้:

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")))
Sudheer Aedama

1
@VenkatSudheerReddyAedama การเปลี่ยนตำแหน่งของเมทริกซ์ที่ไม่สมบูรณ์ไม่สมเหตุสมผลสำหรับฉัน ในการใช้ตัวอย่างของคุณถ้าcสอดคล้องกับaหรือกับb? และคุณจะแสดงให้สอดคล้องกับอีกฝ่ายอย่างไร?
Daniel C. Sobral

เห็นด้วย นั่นคือเมทริกซ์ที่ไม่สมบูรณ์ ฉันกำลังมองหาบางอย่างตามแนวของ zipAll พูดในกรณีของฉันcสอดคล้องกับa(กล่าวคือในแนวเดียวกับดัชนี)?
Sudheer Aedama


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.