Home > OS >  Comparing string numbers in Scala
Comparing string numbers in Scala

Time:07-05

I have a usage case like;

val fieldType = "int" // we know what is the type of field
val value1 = "1" // can be double/int/long/float etc.
val value2 = "2" // can be double/int/long/float etc.

val operator = "=" // can be >, >=, <, <= etc.

def compare(operator, value1, value2): Boolean = {}

Couldn't find a good way to do this. Is there any way to do this efficiently?

EDIT

I've just made this one but not sure this is the most efficient way;


  private def apply(fieldType: String, operator: String, value1: String, value2: String): Boolean =
    operator match {
      case ">" =>
        compare(fieldType, value1, value2) > 0
      case ">=" =>
        compare(fieldType, value1, value2) >= 0
      case "<" =>
        compare(fieldType, value1, value2) < 0
      case "<=" =>
        compare(fieldType, value1, value2) <= 0
      case "==" =>
        compare(fieldType, value1, value2) == 0
    }

  private def compare(fieldType: String, value1: String, value2: String): Int =
    fieldType match {
      case "string"     => value1.compareTo(value2)
      case "int"        => value1.toInt.compareTo(value2.toInt)
      case "long"       => value1.toLong.compareTo(value2.toLong)
      case "float"      => value1.toFloat.compareTo(value2.toFloat)
     
    }

CodePudding user response:

The advantage of this solution is that it's generic, so it will work for all numeric types.

I'm using the implicit ordering that Scala provides for every numeric type. And I provide a generic compare method that works for very numeric type. But I still had to parse fieldType to figure out what types I should compare.

T : Ordering means a context bound - this avoids the explicit use of an implicit parameter in the method, and lets Scala provide one of type Ordering[T] automatically wherever I need it in the body of the method.

implicitly[Ordering[T] is a standard library method that tells Scala to look for an implicit definition of type Ordering[T], call it, and return the object right back, then use the methods defined in trait Ordering for comparation purposes.

These 2 ideas fuse together to eliminate the need to include an implicit parameter for the method, because we are not interested in an explicit ordering parameter:

  def compareBy(fieldType: String)(
      op: String,
      a: String,
      b: String
  ): Boolean = {
    def compare[T: Ordering](op: String, a: T, b: T): Boolean =
      op match {
        case "==" => implicitly[Ordering[T]].eq(a, b)
        case "<"  => implicitly[Ordering[T]].lt(a, b)
        case "<=" => implicitly[Ordering[T]].lteq(a, b)
        case ">"  => implicitly[Ordering[T]].gt(a, b)
        case ">=" => implicitly[Ordering[T]].gteq(a, b)
        case _    => throw new UnsupportedOperationException("op not supported!")
      }

    fieldType match {
      case "byte"   => compare(op, a.toByte, b.toByte)
      case "short"  => compare(op, a.toShort, b.toShort)
      case "int"    => compare(op, a.toInt, b.toInt)
      case "long"   => compare(op, a.toLong, b.toLong)
      case "float"  => compare(op, a.toFloat, b.toFloat)
      case "double" => compare(op, a.toDouble, b.toDouble)
      case _ =>
        throw new UnsupportedOperationException("fieldType not supported!")
    }
  }

  val a = "10"
  val b = "2"
  val op = ">"
  val intFieldType = "int"
  val compareInts = compareBy(intFieldType) _

  println(compareInts(op, a, b))     // true
  • Related