2016-02-15 26 views
10

Giả sử chúng ta có các danh mục sau kích thước khác nhau:Zip hai danh sách có độ dài khác nhau với yếu tố mặc định để điền

val list1 = ("a", "b", "c") 
val list2 = ("x", "y") 

Bây giờ tôi muốn kết hợp 2 liệt kê những điều này và tạo ra một danh sách mới với các yếu tố chuỗi được nối :

val desiredResult = ("ax", "by", "c") 

tôi đã cố gắng

val wrongResult = (list1, list2).zipped map (_ + _) 

như đề xuất here, nhưng điều này không hoạt động như dự định, vì zip loại bỏ các thành phần đó trong danh sách dài hơn không thể khớp được.

Làm cách nào để giải quyết vấn đề này? Có cách nào để zip danh sách và đưa ra một "yếu tố mặc định" (như chuỗi rỗng trong trường hợp này) nếu một danh sách dài hơn?

Trả lời

26

Phương pháp bạn đang tìm kiếm là .zipAll:

scala> val list1 = List("a", "b", "c") 
list1: List[String] = List(a, b, c) 

scala> val list2 = List("x", "y") 
list2: List[String] = List(x, y) 

scala> list1.zipAll(list2, "", "") 
res0: List[(String, String)] = List((a,x), (b,y), (c,"")) 

.zipAll mất 3 đối số:

  • các iterable để zip với
  • giá trị mặc định nếu this (bộ sưu tập .zipAll được gọi) ngắn hơn
  • giá trị mặc định nếu bộ sưu tập khác là ngắn hơn
+1

Tôi đoán luôn có điều gì đó mà bạn không biết. –

+0

Cảm ơn! Bây giờ nó làm việc với giải pháp này: 'list1.zipAll (list2," "," ") map ({case (y, x) => y + x})' nhưng không giống như trước với 'list1.zipAll (list2," "," ") bản đồ (_ + _)'. Tại sao tôi không thể sử dụng cú pháp ngắn với zipAll như chức năng nén? – ForceOfWill

+1

@ForceOfWill: '(list1, list2) .zipped' trả về' Tuple2Zipped', trong đó ['.map'] (http://www.scala-lang.org/api/current/index.html#scala.runtime .Tuple2Zipped @ map [B, To] (f: (El1, El2) => B) (implicitcbf: scala.collection.generic.CanBuildFrom [Repr1, B, To]): Tới) lấy một 'f: (El1, El2) => B' (tức là một hàm lấy 2 đối số). '' '' '' Của 'List [a]' có một 'f: A => B', nghĩa là chỉ có 1 đối số (trong trường hợp này là' Tuple2'). Thật không may điều này có nghĩa là '_ + _' (là một hàm nhận 2 đối số) không thể được áp dụng ở đây. – Marth

2

API dựa trên zipAll là con đường để đi, nhưng bạn có thể thực hiện nó (như một bài tập) ví dụ như sau,

implicit class OpsSeq[A,B](val xs: Seq[A]) extends AnyVal { 
    def zipAll2(ys: Seq[B], xDefault: A, yDefault: B) = { 
    val xs2 = xs ++ Seq.fill(ys.size-xs.size)(xDefault) 
    val ys2 = ys ++ Seq.fill(xs.size-ys.size)(yDefault) 
    xs2.zip(ys2) 
    } 
} 

Do đó ví dụ

Seq(1,2).zipAll2(Seq(3,4,5),10,20) 
List((1,3), (2,4), (10,5)) 

list1.zipAll2(list2, "", "") 
List((a,x), (b,y), (c,"")) 

Một phiên bản đệ quy,

def zipAll3[A,B](xs: Seq[A], ys: Seq[B], xd: A, yd: B): Seq[(A,B)] = { 
    (xs,ys) match { 
    case (Seq(), Seq()) => Seq() 
    case (x +: xss, Seq()) => (x,yd) +: zipAll3(xss, Seq(), xd, yd) 
    case (Seq(), y +: yss) => (xd,y) +: zipAll3(Seq(), yss, xd, yd) 
    case (x +: xss, y +: yss) => (x,y) +: zipAll3(xss, yss, xd, yd) 
    } 
} 

với mặc định xd và mặc định yd giá trị.

Các vấn đề liên quan