-8

2 つの数値を比較する方法を教えてください。任意の数字。のようIntFloat?複素数などとの比較には興味がありません。比較したいのは、比較可能なものだけです。Float と Int です。

次のものがあるとします。

def compareTwoNumbers[???](array:Array[???], number:???) = {
    array(0) > number // this has to compile
}

の代わりに何を書く???

私がこれまでに試したこと:

  1. Number.
  2. T <: Number
  3. Numeric(申し訳ありませんが、この状況での使用方法がわかりません。例がありません/ドキュメントが貧弱すぎます)。
4

6 に答える 6

4

主な問題は数値型の変換だと思います。それでは、それをエンコードしましょう:

trait NumericConversion[X, Y] {
  def convert(x: X): Y
}

もちろん、その抽象的な概念を指定する必要があります: (たとえば)

implicit object Int2IntNumericConversion extends NumericConversion[Int, Int] {
  def convert(i: Int): Int = i
}
implicit object Double2DoubleNumericConversion extends NumericConversion[Double, Double] {
  def convert(d: Double): Double = d
}
implicit object Int2DoubleNumericConversion extends NumericConversion[Int, Double] {
  def convert(i: Int): Double = i.toDouble
}

比較方法は次のようになります。

def compareTwoNumbers1[N1, N2, N3](n1: N1, n2: N2)
                                  (implicit conv1: NumericConversion[N1, N3], 
                                            conv2: NumericConversion[N2, N3], 
                                              ord: Ordering[N3]): Int = {
  ord compare (conv1 convert n1, conv2 convert n2)
}

使用法:

compareTwoNumbers1[Int, Double, Double](3, 8D)  // -1

残念なことに、型パラメーターを明示的に指定する必要があるため、次のことを試しました。

def compareTwoNumbers2[N3] = new {
  def apply[N1, N2](n1: N1, n2: N2)(implicit conv1: NumericConversion[N1, N3],
                                             conv2: NumericConversion[N2, N3], 
                                               ord: Ordering[N3]): Int = {
    ord compare (conv1 convert n1, conv2 convert n2)
  }
}

これは、1 つの型引数に縮小されます。

compareTwoNumbers2[Double](3, 8D)  // -1

満足できないので、これを試しました:

trait NumericUpperBound[Num1, Num2, UpperBound]
implicit object NumericUpperBoundIDD extends NumericUpperBound[Int, Double, Double]
implicit object NumericUpperBoundDID extends NumericUpperBound[Double, Int, Double]

新しい比較方法:

def compareTwoNumbers3[N1, N2, N3](n1: N1, n2: N2)
                                 (implicit nub: NumericUpperBound[N1, N2, N3], 
                                         conv1: NumericConversion[N1, N3], 
                                         conv2: NumericConversion[N2, N3], 
                                           ord: Ordering[N3]): Int = {
  ord compare (conv1 convert n1, conv2 convert n2)
}

今では動作します:

compareTwoNumbers3(3, 8D)  // -1

もちろん、すべてのプリミティブの型クラスを作成する必要があります。BigIntただし、後で などに拡張することは柔軟です。

編集

@wvxvw によるコメントは、マトリックスをNumericUpperBounds回避するように私にインスピレーションを与えました。ByteShort

trait ==>[X, Y] extends (X => Y)

object ==> {
  def apply[X, Y](f: X => Y): X ==> Y = {
    new (X ==> Y) {
      def apply(x: X): Y = f(x)
    }
  }
}

implicit val Int2LongNumericConversion = ==> { x: Int => x.toLong }
implicit val Int2FloatNumericConversion = ==> { x: Int => x.toFloat }
implicit val Int2DoubleNumericConversion = ==> { x: Int => x.toDouble }
implicit val Long2FloatNumericConversion = ==> { x: Long => x.toFloat }
implicit val Long2DoubleNumericConversion = ==> { x: Long => x.toDouble }
implicit val Float2DoubleNumericConversion = ==> { x: Float => x.toDouble }
implicit def reflexiveNumericConversion[X]: X ==> X = new (X ==> X) { def apply(x: X): X = x }

trait NumericUpperBound[Num1, Num2, UpperBound]

implicit def reflexiveNumericUpperBound[X]: NumericUpperBound[X, X, X] = new NumericUpperBound[X, X, X] {}
implicit def inductiveNumericUpperBound1[X, Y](implicit ev: X ==> Y): NumericUpperBound[Y, X, Y] = new NumericUpperBound[Y, X, Y] {}
implicit def inductiveNumericUpperBound2[X, Y](implicit ev: X ==> Y): NumericUpperBound[X, Y, Y] = new NumericUpperBound[X, Y, Y] {}

def compareTwoNumbers[N1, N2, N3](n1: N1, n2: N2)
                                 (implicit nub: NumericUpperBound[N1, N2, N3], 
                                         conv1: N1 ==> N3, 
                                         conv2: N2 ==> N3, 
                                           ord: Ordering[N3]): Int = {
  ord compare (n1, n2)
}

compareTwoNumbers(9L, 13) // -1
于 2013-04-01T10:22:40.447 に答える
4

私は現在Scalaを学んでいるので、私の答えをあまり真剣に受け止めないでください.View BoundsまたはType Constraintsがあなたを助けることができると思います. ビュー バウンドを使用すると、それらの間に暗黙的なビューがあるため、標準の数値を比較できますが、BigInt から BigDecimal への暗黙的なビューがないため、それ以上は進みません。

def compareTwoNumbers[A <% Double, B <% Double](array:Array[A], number:B) = array(0) > number

scala> compareTwoNumbers(Array(1, 2, 0), 0.99)
res1: Boolean = true

scala> compareTwoNumbers(Array(1.0, 2, 0), 0.99)
res2: Boolean = true

scala> compareTwoNumbers(Array(1.0, 2, 0), 1)
res3: Boolean = false

BigInt と BigDecimal がサポートされているかどうかを確認し、私のソリューションの欠点を知りたいです。

于 2013-04-01T11:01:34.940 に答える
2

ここにあります:

def cmp[T1, T2](arr: Array[T1], num: T2)
       (implicit v12: T1 => T2 = null, v21: T2 => T1 = null,
        ord1: Ordering[T1], ord2: Ordering[T2]): Boolean = v12 match {
    case null => ord1.gt(arr(0), num)
    case _    => ord2.gt(arr(0), num)
  }

いくつかの使用例:

scala> cmp(Array(1,2), 0.1)  //T1 = Int, T2 = Double 
res3: Boolean = true

scala> cmp(Array(1.2, 2.3), 1) //T1 = Double, T2 = Int 
res4: Boolean = true

scala> cmp(Array(1,2), BigInt(100))  //T1 = Int, T2 = BigInt 
res5: Boolean = false

scala> cmp(Array(123.5 ,2233.9), BigDecimal(100)) //T1 = Double, T2 = BigDecimal 
res6: Boolean = true

scala> cmp(Array(123.5 ,2233.9), 200.toByte) 
res7: Boolean = true
于 2013-04-01T12:18:07.767 に答える
1
def compareTwoNumbers(a: Number, b: Number) = {
  a.floatValue() > b.floatValue() // this has to compile
}
于 2013-03-31T22:52:34.293 に答える
0

このコードを採用するのはそれほど難しいことではありません:

def gt[A : Numeric, B: Numeric](first: A, second: B) = {
    val a = implicitly[Numeric[A]].toDouble(first)
    val b = implicitly[Numeric[B]].toDouble(second)
    a > b
}

さまざまな種類の数値で動作する必要があります。

scala> gt(4, 4.0)
res3: Boolean = false

scala> gt(4, 3.0)
res4: Boolean = true

scala> gt(3L, 4.0)
res5: Boolean = false
于 2013-04-01T09:27:29.107 に答える