Question

I have some data as .csv. It gets input by hand into Excel, and I have to load it into a Scala program.

Most of the fields of a single record are a freetext string or a number, but a few ones come from a prespecified short list of possible strings. I created enumerations for this type of information, like

object ScaleType extends Enumeration {
    val unknown = Value("unknown")
    val nominal = Value("nominal")
    val ordinal = Value("ordinal")
    val interval = Value("interval")
    val ratio = Value("ratio")
}

I read the csv into an Iterator[Array[String]], and for each line, I create new instance of a scala class, setting its properties from the information in the line. Assume that in the csv, it is line(8) which tells us the scale type we used. So, line is an Array[String], line(8) is a string, and its content should be one of the values listed in the enumeration.

As the data is input by hand, it contains errors. I used an if statement to find out if line(8) is completely empty, but I can't figure out how to see if the string I am getting is a scale type at all.

val scale = if(line(8).length > 0)
            {
                ScaleType.withName(line(8))
            }
        else ScaleType.unknown

What I'd like to happen: If somebody has entered the scale type "rtnl", I want the above to set the val scale to ScaleType.unknown and log the problem (something like print("scale reading error on line " + lineNumber will be enough). Instead, an exception gets thrown and I don't know how to check for a problem before the exception happens.

Was it helpful?

Solution

You could use ValueSet.find:

val scale = ScaleType.values.find(_.toString == line(8)).getOrElse(ScaleType.unknown)

if this is too inefficient you could create a map:

val lookup = ScaleType.values.map(v => (v.toString, v)).toMap
val scale = lookup.get(line(8)).getOrElse(ScaleType.unknown)

OTHER TIPS

all you need is a try catch statement.

In java you can extend enums. I am not sure if its the same for scala.

Though you cant remove the exception for valueOf, you can however, choose to use a different method written by you.

If you can do something like this in scala, this will keep your implementation clean, and encapsulate the issue within the scale type enum itself.

public enum ScaleType{
    UNKNOWN,
    NOMINAL,
    ORDINAL, 
    RATIONAL;

    public static ScaleType getScaleTypeFor(String line){
        if(!StringUtils.isBlank(line)){
            try{
              return ScaleType.valueOf(line.toUpperCase());
            }catch(Exception e){
              System.out.println("Unknown scale type found actual value: " + line);
              return ScaleType.UNKNOWN;
            }
        }
        return ScaleType.UNKNOWN;
    }
} 

Just for completeness, as the other solutions are quite good:

You also could use the functional error handling, that is part of Scala sine 2.10. The Try will wrap the result and you will either get an Success[ ScalaType.Value ] or an Failure[ Error ].

import scala.util.Try
def byNameFunctional(name: String) = Try( ScaleType.withName(name) )

Examples:

scala> byNameFunctional("nominal")
res2: scala.util.Try[ScaleType.Value] = Success(nominal)

scala> byNameFunctional("blah")
res3: scala.util.Try[ScaleType.Value] = Failure(java.util.NoSuchElementException: None.get)

A nice addition is that you can match and map over the results, and the error is kept in the result:

scala> byNameFunctional("nominal") map (_.toString + "!!!")
res5: scala.util.Try[String] = Success(nominal!!!)

scala> byNameFunctional("nominal123") map (_.toString + "!!!")
res6: scala.util.Try[String] = Failure(java.util.NoSuchElementException: None.get)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top