Преобразовать числовой тип в двойной без параметра - PullRequest
2 голосов
/ 22 сентября 2019

Я пытаюсь реализовать универсальный метод для вычисления среднего значения любой последовательности (например, List, Array), которая содержит числовые значения любого типа (Int, Float, Double ...), например:


 def mean[T <: Numeric[T]](data:Seq[T])(implicit number: Numeric[T]): T = {
      data.foldLeft(number.zero)(number.plus) / data.size
  }

Однако операция разделения не может быть решена.Это связано с тем, что для числового типа эта операция не определена (из ScalaDoc ).Я хочу преобразовать его в удвоение, прежде чем продолжить деление, но метод toDouble(x:T) из числового типа ожидает param.Я видел, что есть тип для Numeric [T] с именем NumericOps, который реализует метод toDouble без получения каких-либо параметров.Могу ли я назвать этот метод .. как-нибудь?

Ответы [ 3 ]

4 голосов
/ 22 сентября 2019

Вот пример использования Fractional , он сохранит правильную точность введенных чисел и выполнит только один обход данных.Однако обратите внимание, что это работает только для типов, которые имеют «точное» деление , например Float, Double & BigDecimal.Но не работает для числовых типов, таких как Int или Long.

def mean[T](data: Iterable[T])(implicit N: Fractional[T]): T = {
  import N._

  val remaining = data.iterator

  @annotation.tailrec
  def loop(sum: T, count: Int): T =
    if (remaining.hasNext)
      loop(sum + remaining.next(), count + 1)
    else if (count == 0)
      zero
    else
      sum / fromInt(count)

  loop(zero, 0)
}

Это было проверено на Scala 2.13.

3 голосов
/ 22 сентября 2019

Если точность Double достаточна, попробуйте

def mean[T](data: Seq[T])(implicit number: Numeric[T]): Double = {
  import number._
  val sum = data.foldLeft(zero)(plus) 
  toDouble(sum) / data.size
}

mean(Seq(1,2,3,4)) // 2.5

или используйте Fractional (но это не будет работать для Ints)

def mean[T](data: Seq[T])(implicit number: Fractional[T]): T = {
  import number._
  val sum = data.foldLeft(zero)(plus)
  div(sum, fromInt(data.size))
}

mean(Seq(1.0,2,3,4)) // 2.5
mean(Seq(1,2,3,4))   // error: could not find implicit value for parameter number: Fractional[Int]
2 голосов
/ 22 сентября 2019

Если вам не нужно использовать Numeric, почему бы просто не использовать Fractional, поскольку это добавляет операцию div к Numeric.

. Это может вас заинтересовать, когда они говорят о различных опциях:

https://stackoverflow.com/a/40351867/67566

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...