2012-06-19 29 views
13

Với hai tuples của cùng một arity, làm thế nào tôi có thể so sánh theo từ điển? Dường như việc này đơn giản như trong đoạn mã sau, nhưng không phải vậy. Bất kỳ ví dụ đơn giản nào về cách thực hiện?Làm thế nào để so sánh từ điển so với scala tuple?

var x = (1,2,3) < (1,2,4) 

Were họ liệt kê, tôi có thể định nghĩa một hàm đệ quy đó sẽ so sánh đầu danh sách cho đến khi một sự khác biệt hoặc kết thúc của một danh sách đã được tìm thấy, nhưng tôi không nghĩ rằng tôi có thể làm điều đó cho các bộ.

Trả lời

22

Nó không phải đơn giản vì khi

var x = (1,2,3) < (1,2) 

trông khá đơn giản,

var x = (1,false,3) < (1,2) 

thì không. Làm thế nào để bạn đối phó với các loại không được đặt hàng? Làm thế nào để bạn đối phó với các loại khác nhau trong cùng một vị trí tuple?

Bạn có ủy quyền tất cả các loại giống nhau không? Trong trường hợp đó, bạn không có tuple. Toàn bộ các điểm của một tuple là arity của nó là cố định (bạn tĩnh biết nó lớn như thế nào) và mỗi phần tử có thể là một loại khác nhau.

Nếu tôi thấy mình gặp vấn đề đó - và tôi sẽ cố gắng hết sức để không - tôi sẽ lấy Shapeless, chuyển các bộ dữ liệu thành thứ gì đó như HList, và sau đó thử so sánh nó.

EDIT

Ah, bây giờ nó là dễ dàng hơn nhiều:

import scala.math.Ordering.Implicits._ 
var x = (1,2,3) < (1,2,4) 

Những implicits thêm không tự động có sẵn vì chúng có thể gây ra phân kỳ implicits dưới một số trường hợp.

+0

Điểm tốt, Daniel. Tôi đã chỉnh sửa câu hỏi của tôi để nhà nước so sánh tuples luôn luôn có cùng một arity. Đối với các loại không được đặt hàng, các bộ dữ liệu của tôi phải có các ký hiệu (đó là lý do tôi chuyển sang các bộ dữ liệu thay vì danh sách), nhưng vì tôi không tìm thấy bất kỳ cách nào để đặt các biểu tượng, thay vào đó, tôi sử dụng các số. Tôi có nên sử dụng danh sách không? Nếu tôi thực sự cần thêm biểu tượng vào danh sách thì sao? – lasaro

+1

@lasaro Vâng, bây giờ bạn đã đơn giản hóa vấn đề, có một giải pháp tương đối dễ dàng. Xem câu trả lời đã chỉnh sửa. –

+0

Cảm ơn Daniel, cho bạn ví dụ rất ngắn gọn. – lasaro

2

Cách dễ nhất là xác định Thứ tự ngầm định [T] trên chúng, nhưng sau đó bạn phải chuyển thứ tự này tới hàm sắp xếp (hoặc bất kỳ hàm nào khác muốn so sánh chúng). Nó cũng có thể vượt qua nó hoàn toàn.

Một cách khác sẽ được, để mở rộng các lớp tuple bởi các nhà điều hành < thông qua một diễn viên tiềm ẩn:

implicit def compareTuple[T](lhs: (T,T)) = new { 
    def <(rhs: (T,T)) = lhs._1<rhs._1 || (lhs._1==rhs._1 && lhs._2<rhs._2) 
} 

chỉnh sửa: Nếu bạn muốn có những toán tử so sánh khác nữa, bạn có thể nhận được chúng bởi kế thừa từ Ordered [T]:

implicit def compareTuple[T](lhs: (T,T)) = new Ordered[(T,T)] { 
    def compare(rhs: (T,T)) = ... 
} 

edit2: Nếu bạn cũng cần phải so sánh các tuple các kích thước khác nhau, bạn có thể sử dụng hàm productIterator được định nghĩa trong tất cả các lớp tuple (see documentation) và cho phép bạn có được một trình lặp trên bộ tuple. Bằng cách này bạn có thể viết một hàm giống như bạn sẽ làm nó với một danh sách.

EDIT3: Đây sẽ là một cái gì đó như:

implicit def compareTuple[T <: Product](lhs: T) = new Ordered[T] { 
    def compare[U <: Product](rhs: U) = { 
     def compare(lhs: Any, rhs: Any) = ... 
     def iteratorCompare(lhs: Iterator[Any], rhs: Iterator[Any]):Int = 
      if(!lhs.hasNext) 
       if(!rhs.hasNext) 
        0 
       else 
        -1 
      else if(!rhs.hasNext) 
       1 
      else 
       compare(lhs.next,rhs.next) 
     iteratorCompare(lhs.productIterator,rhs.productIterator) 
    } 
} 

Nhưng với phương pháp này bạn phải chăm sóc về các loại. Bởi vì hàm không biết các kiểu phần tử tuple (chúng có thể khác nhau bên trong cùng một bộ), nó chỉ có thể cung cấp cho bạn một Iterator [Any]. Vì vậy, bạn phải xác định một so sánh (Bất kỳ, Bất kỳ) chức năng để xử lý những gì bạn muốn.

+1

Bạn có thể bật '-Xexperimental' để chọn LUB thay vì' Bất kỳ'. – soc

+0

Cảm ơn Heinzi, vì câu trả lời hoàn chỉnh của bạn. Tôi đã học được rất nhiều từ nó, nhưng đối với cấp độ của câu hỏi của tôi và kỹ năng scala, Daniel đã được nhiều điểm. – lasaro

9

Giải pháp của Daniel hoạt động nếu bạn muốn sử dụng < nhưng nếu bạn cần phương pháp compare, bạn có thể thực hiện các thao tác sau (ví dụ).

implicitly[Ordering[Tuple2[Int, Int]]].compare((1,2), (2,3)) 

Có các đơn đặt hàng được xác định cho tất cả các bộ dữ liệu có các bộ phận tương đương.

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