Đây là cách tôi định nghĩa nó trong mã của tôi.
Thay vì sử dụng Numeric
, tôi sử dụng Fractional
, vì Fractional
xác định thao tác chia (Numeric
không nhất thiết phải có bộ phận). Điều này có nghĩa là khi bạn gọi số .avg
, bạn sẽ lấy lại cùng loại mà bạn đã nhập, thay vì luôn nhận được Double
.
Tôi cũng xác định nó trên tất cả các bộ sưu tập GenTraversableOnce
để nó hoạt động trên, ví dụ: Iterator
.
class EnrichedAvgFractional[A](self: GenTraversableOnce[A]) {
def avg(implicit num: Fractional[A]) = {
val (total, count) = self.toIterator.foldLeft((num.zero, num.zero)) {
case ((total, count), x) => (num.plus(total, x), num.plus(count, num.one))
}
num.div(total, count)
}
}
implicit def enrichAvgFractional[A: Fractional](self: GenTraversableOnce[A]) = new EnrichedAvgFractional(self)
Thông báo như thế nào nếu chúng ta cung cấp cho nó một bộ sưu tập của Double
, chúng tôi nhận lại Double
và nếu chúng ta cung cấp cho nó BigDecimal
, chúng tôi nhận lại BigDecimal
. Chúng tôi thậm chí có thể xác định loại số Fractional
của riêng mình (đôi khi tôi thực hiện) và nó sẽ hoạt động cho điều đó.
scala> Iterator(1.0, 2.0, 3.0, 4.0, 5.0).avg
res0: Double = 3.0
scala> Iterator(1.0, 2.0, 3.0, 4.0, 5.0).map(BigDecimal(_)).avg
res1: scala.math.BigDecimal = 3.0
Tuy nhiên, Int
không phải là một loại Fractional
, có nghĩa là nó không có ý nghĩa để có được một Int
và kết quả của trung bình Int
s, vì vậy chúng tôi cần phải có một trường hợp đặc biệt cho Int
có thể chuyển đổi để a Double
.
class EnrichedAvgInt(self: GenTraversableOnce[Int]) {
def avg = {
val (total, count) = self.toIterator.foldLeft(0, 0) {
case ((total, count), x) => (total + x, count + 1)
}
total.toDouble/count
}
}
implicit def enrichAvgInt(self: GenTraversableOnce[Int]) = new EnrichedAvgInt(self)
Vì vậy, trung bình Int
s cho chúng ta một Double
:
scala> Iterator(1, 2, 3, 4, 5).avg
res2: Double = 3
lớp 'ngầm IterebleWithAvg [T: Numeric] (dữ liệu: Iterable [T]) {def AVG = trung bình (dữ liệu)}' nên được ưa thích kể từ hôm nay. –
Chúng ta cũng nên xử lý không lặp lại độ dài 0, ném một lỗi. – Marboni