8

I need to do some raw data parsing and I am forced to work with Any type.

If the data I read is in any numeric format (Int/Double/Long/...) I need to convert it to Double, otherwise (eg. String) I need to leave it empty.

This is what I came up with:

def extractDouble(expectedNumber: Any): Option[Double] = expectedNumber match {
  case i: Int => Some(i.toDouble)
  case l: Long => Some(l.toDouble)
  case d: Double => Some(d)
  case _ => None
}

This obviously doesn't look even decently. Is there any better way to deal with this in Scala?

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
TheMP
  • 8,257
  • 9
  • 44
  • 73

5 Answers5

11

Once you lost your type information at compile time, as it happens to be in your case since your input type is Any as part of its requirements, there is no more options than inspecting expectedNumber at run time with isInstanceOf.

That is masked by the implementation of type pattern matching you are doing in your proposed solution. And I think that is the best solution in your case.

However, there is an alternative which is using Try over and transforming it into an Option. e.g:

Try(expectedNumber.toString.toDouble).toOption

That's a dirty solution in so many ways (not efficient at all, using exceptions to control flow, ...) that I would definetively use your first approach

4

It is certainly possible, as indicated in this answer:

Use java.lang.Number to match with your case type.

def extractDouble(x: Any): Option[Double] = x match {
  case n: java.lang.Number => Some(n.doubleValue())
  case _ => None
}

Note that this also works for instances of BigDecimal and BigInteger, be it scala.math.BigDecimal or java.math.BigDecimal.

Community
  • 1
  • 1
Adowrath
  • 701
  • 11
  • 24
2

I was using the OP's solution for a while. But upon encountering some slightly corrupted data input, I subsequently changed to a combination of OP's solution and the Try solution.

  def extractDouble(expectedNumber: Any): Option[Double] = expectedNumber match {
    case i: Int => Some(i.toDouble)
    case l: Long => Some(l.toDouble)
    case d: Double => Some(d)
    case s: String => Try(s.trim.toDouble).toOption
    case _ => None
  } 

the case s:String line may save you a bit of debugging and head scratching down the line if you are dealing with big and potentially messy data

Jake
  • 4,322
  • 6
  • 39
  • 83
1

Starting Scala 2.13, we could apply the new String::toDoubleOption after transforming expectedNumber: Any to String:

def extractDouble(expectedNumber: Any): Option[Double] =
  expectedNumber.toString.toDoubleOption

For instance:

extractDouble(12.56d)  // Option[Double] = Some(12.56)
extractDouble(12)      // Option[Double] = Some(12.0)
extractDouble(12L)     // Option[Double] = Some(12.0)
extractDouble("hello") // Option[Double] = None
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
0
import scala.util.Try    
def parseDouble(s: String): Option[Double] = Try { s.toDouble }.toOption

Scala is a string parseable as a double

Community
  • 1
  • 1
Sumon Rahman
  • 99
  • 1
  • 7
  • -1 This does not, or just in part, answer OPs question. They said that they are forced to use the `Any` parameter, and also only works if you have a `String` (which is of course easily achieved, but digresses from the original problem). – Adowrath Feb 24 '17 at 12:14
  • That is good point...the parseDouble can be modified as def parseDouble(s: Any): Option[Double] = Try { s..toString.toDouble }.toOption – Sumon Rahman Feb 24 '17 at 12:49
  • But then, it's roughly the same as Pablo but without the warnings of why it is a bad idea. – Adowrath Feb 24 '17 at 12:56
  • 1
    Fully agree that is an extension of Palbo...I just wanted to share the link that has some examples if that helps. – Sumon Rahman Feb 24 '17 at 13:29