2011-06-18 22 views
6

Tôi có một Danh sách [Số]. Nó chứa các giá trị của các lớp con khác nhau của Number - Int, Double, v.v. Tôi muốn tổng hợp tất cả các giá trị với nhau. Nếu danh sách chỉ chứa Int, tôi muốn kết quả là Int. Nếu có hỗn hợp, tôi muốn làm theo các quy tắc Scala bình thường: Int + Double = Double (và vân vân).Thêm số cùng

Tôi đã thử điều này:

val result = list.reduceLeft(_ + _) 

Đây không phải là thậm chí compilable. Số không có phương thức + được xác định mà cần có một Số khác.

Tôi làm cách nào để thực hiện việc này?

Andrés

+1

để tham khảo trong tương lai, nó được coi là hình thức tốt hơn để hỏi. một câu hỏi _either_ trên danh sách gửi thư của Scala _or_ StackOverflow, không phải cả hai. Đối với các câu hỏi như thế này trong đặc biệt lar, StackOverflow thường là sự lựa chọn tốt hơn, vì nó dễ dàng hơn cho những người khác học hỏi từ câu hỏi và câu trả lời ở đây hơn là trên lưu trữ danh sách gửi thư! –

+1

Tôi đã sửa chữa. Nó sẽ không xảy ra nữa đâu. Cảm ơn tất cả sự giúp đỡ và vì đã nhẹ nhàng trong việc dạy tôi netiquette. – Andres

Trả lời

9

Sao chép câu trả lời của tôi từ mailing list Scala nơi câu hỏi lần đầu tiên được hỏi:

Number là một lớp Java, và không có chức năng ngoài việc chuyển đổi bản thân để loại nguyên thủy. Thật không may, Scala của AnyVal không làm bất cứ điều gì ngoài việc đánh dấu các loại nguyên thủy, và Numeric[T] từ Scala chỉ biết về loại riêng của nó, không phải là một kết hợp của các loại.

Vì vậy, bạn đã để lại kết hợp mẫu tương đối khó chịu; cú pháp ngắn nhất nếu bạn chắc chắn bạn chỉ cần xử lý gấp đôi và int là:

list.reduceLeft((l,r) => (l: Any, r: Any) match { 
    case (li: Int, ri: Int) => li + ri 
    case _ => l.doubleValue + r.doubleValue 
}) 

Lưu ý rằng tôi đúc để Any để có được những mô hình phù hợp Scala để làm unboxing cho chúng ta; nếu bạn để nó như là Số, bạn phải kết hợp mẫu trên java.lang.Integer và sau đó valueOf nó, đó là một nỗi đau.

Nếu bạn muốn biết thêm bạn sẽ phải xây dựng trong chương trình khuyến mãi phù hợp:

list.reduceLeft((l,r) => (l: Any) match { 
    case li: Int => (r: Any) match { 
    case ri: Int => li + ri 
    case rf: Float => li + rf 
    case rl: Long => li + rl 
    case _ => li + r.doubleValue 
    } 
    case lf: Float => /* etc. */ 
}) 

Nếu bạn phải làm điều này hơn một chút, bạn có lẽ tốt hơn bỏ Numeric ủng hộ của riêng bạn các lớp bao bọc mà biết cách thêm chính mình cùng với quảng cáo phù hợp; sau đó bạn có thể viết mẫu phù hợp với chỉ một lần và quay trở lại sử dụng + trong danh sách của bạn comprehensions.

sealed abstract class Addable { 
    def +(a: Addable): Addable 
} 

final case class MyInt(value: Int) extends Addable { 
    def +(a: Addable) = a match { 
    case MyInt(i) => MyInt(value + i) 
    case MyFloat(f) => MyFloat(value + f) 
    ... 
    } 
} 

final case class MyFloat(value: Float) extends Addable { 
    def +(a: Addable) = a match { 
    case MyInt(i) => MyFloat(value + i) 
    ... 
    } 
} 

... 

Một ưu điểm nhẹ của phương pháp này là bạn có thể quyết định để phát huy giá trị một cách khác so với tiêu chuẩn (ví dụ, bạn có thể quyết định rằng phao + dài = đôi, từ một phao thực sự không được cắt ra . để giữ phần lớn chính xác số dài, và làm MyDouble(value.toDouble + f.toDouble), ví dụ

đó là tất cả khá vụng về; không phải Java cũng không Scala thực sự cung cấp hỗ trợ cho hỗn hợp kiểu toán học

0

Bằng cách giảm một danh sách các Double s.

Không sử dụng lớp Number, bạn thực sự không thể thực hiện bất kỳ thứ gì với nó. Nó thậm chí không phải là một lớp Scala, nó là một lớp Java.

+0

Tôi tự hỏi tại sao bạn bị downvoted. Làm một cái gì đó như 'num.view.map (_. DoubleValue) .sum' là hợp lý ở đây. – soc

+0

@SOC tôi đã làm? Có lẽ đó là một sai lầm. Tôi không thể tìm thấy nó để bỏ phiếu, tôi vẫn còn tương đối mới ở đây. –

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