Home > other >  how to map many strings to integer values in Scala?
how to map many strings to integer values in Scala?

Time:01-17

I have the following use case. User is providing two kinds of strings type and growth I need to convert the value of each into an integer from a known map and return the sum of both value.

What I did to map the strings is:

object Types extends Enumeration {

  val T1 = 5
  val T2 = 6
  // list of values is really long!

  val TYPE1 = "type1"
  val TYPE2 = "type2"
}


object Growth extends Enumeration {

  val G1 = 1
  val G2 = 10
  // list of values is really long!

  val GROWTH1 = "growth1"
  val GROWTH2 = "growth2"
}

Now consider user is calling sum("type1", "growth2") the expected output is 15 because 5 10=15

I wrote this skeleton function but I'm having trouble utilizing the enumeration objects. How can I do this without having so many if/else?

   def sum(type: String, growth: String) : Int = {
      var sum:Int = 0
      ????
      return sum
   }

if my approach is flawed I'm happy to try another

CodePudding user response:

scala.Enumeration doesn't let you use syntax like this

object MyEnum extends Enumeration { 
  val value = "string"
}

It actually requires you to do something more like

object MyEnum extends Enumeration {
  val value = Value("string")
}

and then you are passing not String but MyEnum.Value.

Since you are giving up on passing around Strings (at least in Scala 2, in Scala 3 you have an option to use type MyEnum = "value1" | "value2" and/or opaque type MyEnum), you create a sealed hierarchy instead

sealed abstract class Type(
  val name: String,
  val number: Int
) extends Product with Serializable
object Type {
  case object Type1 extends Type("type1", 5)
  case object Type2 extends Type("type2", 6)
}

sealed abstract class Growth(
  val name: String,
  val number: Int
) extends Product with Serializable
object Growth {
  case object Growth1 extends Growth("growth1", 1)
  case object Growth2 extends Growth("growth2", 10)
}

def sum(`type`: Type, growth: Growth) : Int =
  `type`.number   growth.number

If you needed to construct a collection of all possible values, instead of scala.Enumeration you can use Enumeratum library instead

import enumeratum.values._

// IntEnumEntry and IntEnum specialize for Int
// and it allows to eliminate boxing

// The Int has to be defined as `val value: Int`

// findValues has to called so that the compiler
// can find all instances in the compile-time and
// populate the `values` collection

// Enumeratum then generate a lot of useful methods out of
// this list e.g. `withName` to find enum by its name

sealed abstract class Type(
  val value: Int
) extends IntEnumEntry
object Type extends IntEnum[Type] {
  case object Type1 extends Type(5)
  case object Type2 extends Type(6)

  val values = findValues
}

sealed abstract class Growth(
  val value: Int
) extends IntEnumEntry
object Growth extends IntEnum[Growth] {
  case object Growth1 extends Growth(1)
  case object Growth2 extends Growth(10)

  val values = findValues
}

def sum(`type`: Type, growth: Growth) : Int =
  `type`.value   growth.value

CodePudding user response:

This can be done by create a Map that gives the score for each String:

val scoreMap = Map(
  "type1" -> 5,
  "type2" -> 6,
  "growth1" -> 1,
  "growth2" -> 10,
)

The score can then be computed using foldLeft:

def score(strings: List[String]) =
    strings.foldLeft(0){ case (sum, str) => sum   scoreMap.getOrElse(str, 0) }

score(List("type1", "growth2")) // 15

Values that are missing from the Map have the default value 0.

CodePudding user response:

You can extend the class Val of Enumeration class.

Example:

object Types extends Enumeration {
    final case class Pairing (label: String, value: Int) extends Val (value, label)

    val TYPE1 = Pairing ("type1", 5)
    val TYPE2 = Pairing ("type2", 6)
}

object Growths extends Enumeration {
    final case class Pairing (label: String, value: Int) extends Val (value, label)

    val GROWTH1 = Pairing ("growth1", 1)
    val GROWTH2 = Pairing ("growth2", 10)
}

type Type = Types.Pairing
type Growth = Growths.Pairing

def sum (t: Type, g: Growth): Int = t.id   g.id

// usage:
import Types._
import Growths._

println(sum(TYPE1, GROWTH2)) // => 15

If you wish to use the operator and reuse the val names :

object Types extends Enumeration {
    final case class Pairing (value: Int) extends Val (value) {
        def   (g: Growth): Int = id   g.id
    }

    val type1 = Pairing (5)
    val type2 = Pairing (6)
}

object Growths extends Enumeration {
    final case class Pairing (value: Int) extends Val (value) {
        def   (t: Type): Int = t.id   id
    }

    val growth1 = Pairing (1)
    val growth2 = Pairing (10)
}

type Type = Types.Pairing
type Growth = Growths.Pairing

// usage:
import Types._
import Growths._

println (type1   growth2) // => 15
println (growth1   type2) // => 7

println (growth1) // => "growth1"
  • Related