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