2012-03-09 16 views
30

Tôi cố gắng để zip nhiều chuỗi để tạo thành một tuple dài:Zip nhiều chuỗi

val ints = List(1,2,3) 
val chars = List('a', 'b', 'c') 
val strings = List("Alpha", "Beta", "Gamma") 
val bools = List(true, false, false) 

ints zip chars zip strings zip bools 

Những gì tôi nhận được:

List[(((Int, Char), String), Boolean)] = 
    List((((1,a),Alpha),true), (((2,b),Beta),false), (((3,c),Gamma),false)) 

Tuy nhiên tôi muốn có được một chuỗi các phẳng tuples :

List[(Int, Char, String, Boolean)] = 
    List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false)) 

tôi bây giờ tôi có thể làm:

List(ints, chars, strings, bools).transpose 

Nhưng nó trả về yếu được nhập List[List[Any]]. Ngoài ra tôi có thể làm (ints, chars, strings).zipped, nhưng zipped chỉ hoạt động trên 2 bộ và 3 bộ.

Có cách nào để nén (tùy ý) số chuỗi có độ dài bằng nhau một cách dễ dàng không?

Trả lời

11

Dưới đây là một cách để giải quyết ví dụ của bạn, nhưng đây không phải là một số chuỗi tùy ý.

val ints = List(1,2,3) 
val chars = List('a', 'b', 'c') 
val strings = List("Alpha", "Beta", "Gamma") 
val bools = List(true, false, false) 

val input = ints zip chars zip strings zip bools 

// Flattens a tuple ((A,B),C) into (A,B,C) 
def f2[A,B,C](t: ((A,B),C)) = (t._1._1, t._1._2, t._2) 

// Flattens a tuple ((A,B),C,D) into (A,B,C,D) 
def f3[A,B,C,D](t: ((A,B),C,D)) = (t._1._1, t._1._2, t._2, t._3) 

input map f2 map f3 

Tôi không nghĩ rằng nó có thể làm điều đó một cách tổng quát cho các bộ dữ liệu có độ dài tùy ý, ít nhất là không phải với loại giải pháp này. Tuple được gõ mạnh mẽ và hệ thống kiểu không cho phép bạn chỉ định một số biến của các tham số kiểu, theo như tôi biết, điều này làm cho nó không thể tạo ra một phiên bản tổng quát của f2f3 có một tuple chiều dài tùy ý ((A,B),C,D,...) (sẽ trả về một bộ tóan (A,B,C,D,...)).

Nếu có cách để chỉ định số lượng thông số kiểu biến, chúng tôi sẽ không cần các đặc điểm Tuple1, Tuple2, ... Tuple22 trong thư viện chuẩn của Scala.

+0

+1, cảm ơn. Tôi hiện đang sử dụng cách tiếp cận 'bản đồ', nhưng' t._1._1, t._1._2, t._2, t._3' không dễ đọc - và trong trường hợp của tôi, tôi cần một bộ 5-bit, làm cho vấn đề còn tồi tệ hơn. Tôi không thực sự cần hỗ trợ danh sách dài tùy ý, nhưng * đủ dài *. Mặc dù tôi có thể có một số phương pháp chuyên biệt trả về các bộ dữ liệu có độ chính xác cao, nhưng tôi nhận được điểm của bạn về vấn đề 'Tuple1'-' Tuple22'. –

+6

Với đối sánh mẫu, bạn có thể loại bỏ cú pháp '._1, ._2' vv không đọc được:' def f2 [A, B, C] (t: ((A, B), C)) = t khớp {case ((a, b), c) => (a, b, c)} ' – Jesper

2

Tôi chia sẻ ý kiến ​​của Jesper rằng điều này là không thể nói chung, vì mỗi nhân vật tuple được biểu diễn dưới dạng lớp riêng biệt trong mã nguồn, vì vậy bạn phải viết mã riêng để truy cập chúng trừ khi sử dụng trình tạo mã.

Nhưng tôi muốn thêm một giải pháp khả thi khác. Nếu bạn muốn duy trì việc nhập các mục nhập tuple của bạn, nhưng nếu không quan tâm đến một loại bộ sưu tập giống như nhiều hơn, có thể HLists (danh sách không đồng nhất) là dành cho bạn. Bạn có thể google hlist scala để triển khai và giải thích.

5

Sử dụng shapeless, bạn có thể làm:

import shapeless.Tuples._ 

val ints = (1, 2, 3) 
val chars = ('a', 'b', 'c') 

val megatuple = (ints, chars) 

val megahlist = (megatuple hlisted) map hlisted 

val transposed = (mhlist transpose) map tupled tupled 

scala> transposed 
res: ((Int, Char), (Int, Char), (Int, Char)) = ((1,a),(2,b),(3,c)) 

(không chắc chắn, nếu có nhiều implicts định nghĩa cho phép bạn tránh được những map và back-và-ra chuyển đổi)

[Sửa : Phần này không còn đúng nữa.

Lưu ý rằng tài liệu không có khả năng nói, chỉ chuyển đổi tối đa Tuple4 hiện được hỗ trợ. Bạn sẽ phải tạo thủ công HLists sau đó.]

+0

Trên thực tế không có hình dạng xử lý tất cả các tổ chức lên đến 22. –

+0

Ah, ok. Tôi đã đi theo bình luận trong conversion.scala mà không thực sự kiểm tra nó. – Debilski

+0

Rất tiếc ... đã hết nhận xét. Đã sửa lỗi. Cảm ơn cho những người đứng đầu lên. –

6

tôi sẽ tạo ra một lớp đại diện cho các tập dữ liệu:

case class DataSet(int: Int, char: Char, string: String, bool: Boolean) 

này mang tên đẹp hơn để truy cập vào các giá trị thay vì _N chúng tôi có trong các bộ. Nếu danh sách có thể có kích thước khác nhau ngắn nhất nên được chọn:

val min = List(ints, chars, strings, bools).map(_.size).min 

Bây giờ nó có thể trích xuất các dữ liệu:

val dataSets = (0 until min) map { i => DataSet(ints(i), chars(i), strings(i), bools(i)) } 

Khi danh sách ban đầu có thể chứa rất nhiều giá trị nó là tốt hơn để đặt chúng ở số IndexedSeq để thời gian truy cập là O (1).

1

Sử dụng product-collections

scala> ints flatZip chars flatZip strings flatZip bools 
res0: org.catch22.collections.immutable.CollSeq4[Int,Char,String,Boolean] = 
CollSeq((1,a,Alpha,true), 
     (2,b,Beta,false), 
     (3,c,Gamma,false)) 

này hiện làm việc cho arity 1 - 22. Như bạn có thể nhìn thấy các loại được bảo toàn.

3

Tôi nghĩ rằng mô hình phù hợp là một lựa chọn tốt

val ints = List(1,2,3) 
val chars = List('a', 'b', 'c') 
val strings = List("Alpha", "Beta", "Gamma") 
val bools = List(true, false, false) 
(ints zip chars zip strings zip bools) map { case (((i,c),s),b) => (i,c,s,b)} 

**res1: List[(Int, Char, java.lang.String, Boolean)] = List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false))** 

hoặc bạn có thể thêm loại cũng

(ints zip chars zip strings zip bools) map {case (((i:Int,c:Char),s:String),b:Boolean) => (i,c,s,b)} 

**res2: List[(Int, Char, java.lang.String, Boolean)] = List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false))** 
Các vấn đề liên quan