2011-08-20 29 views
7

Có cách nào để thao tác nhiều giá trị của bộ tuple mà không sử dụng biến tạm thời và bắt đầu một câu lệnh mới không?Thao tuples

Giả sử tôi có phương thức trả về một bộ tuple và tôi muốn làm điều gì đó với các giá trị đó nội dòng.

ví dụ: nếu tôi muốn tách một chuỗi tại một điểm nhất định và đảo ngược các mảnh

def backToFront(s: String, n:Int) = s.splitAt(n)... 

tôi có thể làm

val (a, b) = s.splitAt(n) 
b + a 

(đòi hỏi các biến tạm thời và tuyên bố mới) hoặc

List(s.splitAt(n)).map(i => i._2 + i._1).head 

(công trình , nhưng có vẻ hơi bẩn, tạo một phần tử duy nhất Danh sách chỉ dành cho việc này) hoặc

s.splitAt(n).swap.productIterator.mkString 

(hoạt động cho ví dụ cụ thể này, nhưng chỉ vì có một phương pháp swap làm những gì tôi muốn, vì vậy nó không phải là rất chung chung).

Phương thức zipped trên bộ dữ liệu dường như chỉ dành cho bộ danh sách.

Ví dụ khác, làm cách nào bạn có thể biến tuple ('a, 'b, 'c) thành ('b, 'a, 'c) trong một tuyên bố?

Trả lời

9

Tuples chỉ là kiểu trả về thuận tiện, và nó không được giả định rằng bạn sẽ thực hiện các thao tác phức tạp với nó. Cũng có tương tự discussion trên diễn đàn scala.

Về ví dụ cuối cùng, không thể tìm thấy bất kỳ điều gì tốt hơn so khớp mẫu.

('a, 'b, 'c) match { case (a, b, c) => (b, a ,c) } 
+0

Kết hợp mẫu phù hợp! 's.splitAt (n) khớp với {case (a, b) => b + a}' hoạt động cho phần đầu tiên –

+2

Thật đáng tiếc là không có phương thức 'fold' trong thư viện chuẩn; thì bạn có thể chỉ 's.splitAt (n) .fold ((a, b) => b + a)', và nó cũng hiệu quả hơn. (Vâng, tất nhiên tôi đã tự làm.) –

+0

Fold là tên tốt cho nó. Tôi đã cập nhật câu trả lời của mình. –

7

Thật không may, các phương pháp tích hợp trong bộ dữ liệu là pretty limited.

Có lẽ bạn muốn một cái gì đó như thế này trong thư viện cá nhân của bạn,

def fold2[A, B, C](x: (A, B))(f: (A, B) => C): C = f(x._1, x._2) 
def fold3[A, B, C, D](x: (A, B, C))(f: (A, B, C) => D): D = f(x._1, x._2, x._3) 

Với sự chuyển đổi ngầm thích hợp, bạn có thể làm,

scala> "hello world".splitAt(5).swap.fold(_ + _) 
res1: java.lang.String = " worldhello" 

scala> (1, 2, 3).fold((a, b, c) => (b, c, a)) 
res2: (Int, Int, Int) = (2,3,1) 

Một thay thế cho biểu thức cuối cùng sẽ là "ống "nhà điều hành |> (tải xuống từ Scalaz hoặc here),

scala> ('a, 'b, 'c) |> (t => (t._2, t._3, t._1)) 
res3: (Symbol, Symbol, Symbol) = ('b,'c,'a) 

Điều này sẽ tốt đẹp, nếu không cho các chú thích bắt buộc,

scala> ("hello ", "world") |> (((_: String) + (_: String)).tupled) 
res4: java.lang.String = hello world 
2

Làm thế nào về điều này?

s.splitAt(n) |> Function.tupled(_ + _) 

[Chỉnh sửa: Chỉ cần nhận thấy đối số của bạn cho chức năng được đảo ngược. Trong trường hợp đó, bạn sẽ phải từ bỏ cú pháp giữ chỗ và thay vào đó đi cho: (. Như thể hiện bởi @ 4e6) s.splitAt(n) |> Function.tupled((a, b) => b + a)]

Ví dụ cuối cùng của bạn, không thể nghĩ ra bất cứ điều gì tốt hơn so với một mô hình phù hợp

0

Với phiên bản phát triển hiện nay của shapeless, bạn có thể đạt được điều này mà không cần giải nén các tuple:

import shapeless.syntax.std.tuple._ 

val s = "abcdefgh" 
val n = 3 

s.splitAt(n).rotateRight[shapeless.Nat._1].mkString("", "", "") // "defghabc" 

Tôi nghĩ rằng bạn không cần phải chờ đợi quá lâu (vài ngày tôi muốn nói) trước cú pháp của các phương pháp của dòng cuối cùng được làm sạch và bạn có thể chỉ cần viết

s.splitAt(n).rotateRight(1).mkString