特定の種類のNumber、つまりDouble/Integerでは簡単に問題があるようですが、一般的な場合は書きにくいです。番号(INT、フロート、ダブル、BigDecemial)のいずれかの種類のためにこれを実装する方法スカラーで汎用平均関数を実装する方法は?
implicit def iterebleWithAvg(data:Iterable[Double]) = new {
def avg:Double = data.sum/data.size
}
?
特定の種類のNumber、つまりDouble/Integerでは簡単に問題があるようですが、一般的な場合は書きにくいです。番号(INT、フロート、ダブル、BigDecemial)のいずれかの種類のためにこれを実装する方法スカラーで汎用平均関数を実装する方法は?
implicit def iterebleWithAvg(data:Iterable[Double]) = new {
def avg:Double = data.sum/data.size
}
?
あなたがダブルに合計し、変換ができるようになりますどのNumeric
暗黙的に合格する必要があります。
def average[T](ts: Iterable[T])(implicit num: Numeric[T]) = {
num.toDouble(ts.sum)/ts.size
}
コンパイラはあなたのための正しいインスタンスを提供します:
scala> average(List(1,2,3,4))
res8: Double = 2.5
scala> average(0.1 to 1.1 by 0.05)
res9: Double = 0.6000000000000001
scala> average(Set(BigInt(120), BigInt(1200)))
res10: Double = 660.0
あなたが機能を使用することができます暗黙的なビューを定義します(暗黙の数値依存を伝播する場合)。
implicit def iterebleWithAvg[T:Numeric](data:Iterable[T]) = new {
def avg = average(data)
}
scala> List(1,2,3,4).avg
res13: Double = 2.5
これは私のコードでそれを定義する方法です。
代わりのNumeric
を用いFractional
が除算演算を(Numeric
は必ずしも分割していません)を定義しているので、私は、Fractional
を使用します。つまり、.avg
に電話すると、いつもDouble
になるのではなく、入力したのと同じタイプが返されます。
Iterator
などで動作するように、すべてGenTraversableOnce
コレクションにも定義します。
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)
我々はそれをDouble
のコレクションを与えれば、我々は戻ってDouble
を取得し、我々はそれをBigDecimal
を与えるならば、我々は戻ってBigDecimal
を取得する方法に注意してください。私たちは自分のFractional
という数字の型を定義することもできます(私はときどきそうします)、それはうまくいくでしょう。
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
しかし、Int
は、それがInt
とInt
Sを平均した結果を取得しても意味がないことを意味し、Fractional
の一種ではありませんので、我々はに変換しInt
のための特別なケースを持っている必要があります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)
だからInt
Sを平均すること私たちDouble
を与える:
scala> Iterator(1, 2, 3, 4, 5).avg
res2: Double = 3
'暗黙クラスIterebleWithAvg [T:数値](データ:のIterable [T]){DEF =平均(データ)avgを}'べき今日のように好まれる。 –
また、ゼロ長の繰り返しが可能で、エラーが発生します。 – Marboni