Let's say that I have this class
case class Test (id: Long, name: String)
and an instance of this class :
Test :
id -> 1
name -> toto
I would like to create a Map[String, String] as follow :
Map( "id" -> "1", "name" -> "toto")
My question is : Is there a way to turn this instance of Test into Map[String, String] ? I want to avoid to use a method as this one :
def createMap(instance: Test): Map[String, String] = {
val map = new Map[String, String]
map.put("id", instance.id.toString)
map.put("name", instance.name)
map
}
If there is no method to do so in Scala, is there a way to iterate over class properties ? Maybe I can create a generic function to do so :
def createMap(instance: T): Map[String, String] = {
val map = new Map[String, String]
//pseudocode
for ((name, value) <- instance.getClassProperties.getValues) {
case value.isInstanceOf[String] : map.push(name, value)
case _ : map.push(name, value.toString)
}
map
}
Is that possible ? If you have good examples/links, I'm interested.
A map represents an mapping from keys to values. The Scala Map type has two type parameters, for the key type and for the value type. So a Map[String, Int] maps strings to integers, while a Map[Int, Set[String]] maps integers to sets of strings. Scala provides both immutable and mutable maps.
To convert a list into a map in Scala, we use the toMap method. We must remember that a map contains a pair of values, i.e., key-value pair, whereas a list contains only single values. So we have two ways to do so: Using the zipWithIndex method to add indices as the keys to the list.
To insert the data in the map insert() function in the map is used. It is used to insert elements with a particular key in the map container.
Yes it's possible. Since Scala 2.10 you can use reflection.
Assuming you have:
val test = Test(23423, "sdlkfjlsdk")
The following will get you what you want:
import reflect.runtime.universe._
import reflect.runtime.currentMirror
val r = currentMirror.reflect(test)
r.symbol.typeSignature.members.toStream
.collect{case s : TermSymbol if !s.isMethod => r.reflectField(s)}
.map(r => r.symbol.name.toString.trim -> r.get.toString)
.toMap
To simply iterate over field values of case class use .productIterator
on its instance.
The topic you are dealing with is becoming incredibly recurring on StackOverFlow and the problem is not trivial if you want to have a typesafe implementation.
One way to solve the problem is using reflection (as suggested) but I personally prefer using the type system and implicits.
There is a well-known library, developed by an extremely smart guy, who let you perform advanced operations such as turn any case class into a typesafe heterogeneous list, or create heteregeneous maps, which can be used to implement "extensible records". The library is called Shapeless, and here one example:
object RecordExamples extends App {
import shapeless._
import HList._
import Record._
object author extends Field[String] { override def toString = "Author" }
object title extends Field[String] { override def toString = "Title" }
object id extends Field[Int] { override def toString = "ID" }
object price extends Field[Double] { override def toString = "Price" }
object inPrint extends Field[Boolean] { override def toString = "In print" }
def printBook[B <: HList](b : B)(implicit tl : ToList[B, (Field[_], Any)]) = {
b.toList foreach { case (field, value) => println(field+": "+value) }
println
}
val book =
(author -> "Benjamin Pierce") ::
(title -> "Types and Programming Languages") ::
(id -> 262162091) ::
(price -> 44.11) ::
HNil
printBook(book)
// Read price field
val currentPrice = book.get(price) // Static type is Double
println("Current price is "+currentPrice)
println
// Update price field, relying on static type of currentPrice
val updated = book + (price -> (currentPrice+2.0))
printBook(updated)
// Add a new field
val extended = updated + (inPrint -> true)
printBook(extended)
// Remove a field
val noId = extended - id
printBook(noId)
}
Book behaves like a typesafe map which can indexed using objects as keys. If you are interested in knowing more, a good entry point might be this post:
Are HLists nothing more than a convoluted way of writing tuples?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With