My sample class:
class Thing() {
// Public vars
var one: Int = 1
var two: Int = 2
// Scala-style getter/setter
private var _age: Long = 3
def age: Long = _age
def age_=(a: Long) = _age = a
override def toString(): String = s"one: $one, two: $two, age: $age"
}
// A name -> setter holder class
case class Member(name:String, setter: MethodSymbol)
Now my reflection code and setter invoker:
def analyze[T](classSymbol: ClassSymbol)(implicit tt:TypeTag[T]): List[Member] = {
val tpe = tt.tpe
val classMirror = currentMirror.reflectClass(classSymbol)
tpe.members.filter(p => p.isPublic).collect {
// Ignore the non-methods and methods we don't care about
case (p) if (p.isMethod && tpe.member(TermName(p.name.toString + "_$eq")) != NoSymbol) =>
val setter =
// 1) Scala-stype getters/setters
tpe.members.filter(f => f.name.toString == p.name.toString + "_" && f.isMethod).headOption.map(_.asMethod)
// 2) Public var (no getter/setter)
.orElse(tpe.members.filter(f => f.name.toString == p.name.toString).headOption.map(_.asMethod))
Member(p.name.toString,setter.get)
}.toList
}
def setValue[T](t:T, members: List[Member], field: String, value: Any)(implicit tt:TypeTag[T]) = {
implicit val classTag = ClassTag[T](typeTag[T].mirror.runtimeClass(typeTag[T].tpe))
members.find(_.name == field).map{ m =>
println("--> Setting field "+m.name+" to "+value)
currentMirror.reflect(t).reflectMethod(m.setter)(value)
}
}
And finally my attempted usage:
val obj = new Thing()
println("Before: "+obj)
val members = analyze[Thing](currentMirror.classSymbol(obj.getClass()))
println(members.mkString("\n"))
// Now set some value on a public var
setValue[Thing](obj, members, "one", 99)
println("After: "+obj)
Output shows:
Before: one: 1, two: 2, age: 3
Member(age,method age)
Member(two,variable two)
Member(one,variable one)
--> Setting field one to 99
After: one: 1, two: 2, age: 3
As you can see, reflection correctly differentiated between a getter/setter field and a public var field. Upon attempting to set, it found the field and called the setter w/no exceptions thrown, but... no value actually changed in my object (this is true for either the getter/setter field or var fields). Why am I not seeing the value change?
Found it... posted in case this helps others.
I was filtering on the wrong thing. The setters in Scala have names formatted like "foo_$eq", so I have to look for that pattern. When those methods are called the values in the instance class change as expected. Revised reflection code below:
def analyze[T](classSymbol: ClassSymbol, isGetterSetter:Boolean = false)(implicit tt:TypeTag[T]): List[Member] = {
val tpe = tt.tpe
val Pattern = """(.*)_\$eq""".r
tpe.members.filter(p => p.isPublic).collect {
case p if (p.isMethod && p.name.toString.endsWith("_$eq")) =>
val Pattern(name) = p.name.toString
val setter =
// 1) Scala-stype getters/setters
tpe.members.filter(f => f.name.toString == p.name.toString + "_" && f.isMethod).headOption.map(_.asMethod)
// 2) Public var (no getter/setter)
.orElse(tpe.members.filter(f => f.name.toString == p.name.toString).headOption.map(_.asMethod))
Member(name,setter.get)
}.toList
}
How to apply this class code to a datafile which contains more than one record
class Iris(val sepal_len:Double,val sepal_width:Double,val petal_len:Double,
val petal_width:Double,var sepal_area:Double,val species:String){
require(sepal_area == sepal_len*sepal_width, "wrong values")
def this(sepal_len:Double,
sepal_width:Double,
petal_len:Double,
petal_width:Double,
species:String
) = {
this(sepal_len,sepal_width,petal_len,petal_width,sepal_len * sepal_width,species)
}
override def toString:String = "Iris("+sepal_len+","+sepal_width+","+petal_len+","+petal_width+
","+sepal_area+","+species + ")"
}
val ir = new Iris(1.2,3.4,4.5,5.0,4.08,"setosa")
Iris(1.2,3.4,4.5,5.0,4.08,setosa)
val ir1 = new Iris(1.2,3.4,4.5,5.0,"setosa")
output => ir1: Iris = Iris(1.2,3.4,4.5,5.0,4.08,setosa)
Please give me some idea
Use foreach and for every line create a collection of objects. maybe a list
I would suggest you to use case classed for such data structures and companion object for class overload.
case class Iris(sepal_len: Double, sepal_width: Double, petal_len: Double, petal_width: Double, sepal_area: Double, species: String) {
require(sepal_area == sepal_len * sepal_width, "wrong values")
}
object Iris {
def apply(sepal_len: Double, sepal_width: Double, petal_len: Double, petal_width: Double, species: String) =
new Iris(sepal_len, sepal_width, petal_len, petal_width, sepal_len * sepal_width, species)
}
val ir = Iris(1.2, 3.4, 4.5, 5.0, 4.08, "setosa")
val ir1 = Iris(1.2, 3.4, 4.5, 5.0, "setosa")
I've made the assumption that your sepal_area is not a required field in your class due to your examples and answered accordingly, but if it is required then changing the code will be easy.
In my example answer, I'm storing a collection of Iris. You could alternatively make a case class like:
case class Irises(irises: Seq[Iris])
Example CSV file:
1,5.1,3.5,1.4,5.1,Iris-setosa
2,4.9,3,1.4,9.8,Iris-setosa
3,4.7,3.2,1.3,14.1,Iris-setosa
4,4.6,3.1,1.5,Iris-setosa
5,5,3.6,1.4,25,Iris-setosa
6,5.4,3.9,1.7,32.4,Iris-setosa
Code:
object Demo extends App {
case class Iris(sepal_len: Double, sepal_width: Double, petal_len: Double,
petal_width: Double, var sepal_area: Double = 0, species: String) {
// if undefined on constructing the class
sepal_area = if(sepal_area == 0) sepal_len * sepal_width else sepal_area
def format(double: Double): Double = {
double.round
}
// had weird thing where 4.7 * 3 = 14.100000000000001
require(format(sepal_area) == format(sepal_len * sepal_width), "wrong values")
// using string concatenation looks much more readable
override def toString: String = s"Iris($sepal_len,$sepal_width,$petal_len,$petal_width,$sepal_area,$species)"
}
// file.csv found in {project-name}/file.csv
val bufferedSource = io.Source.fromFile("file.csv")
val seq = bufferedSource.getLines.map {
line =>
// for each line in csv file, split by comma and remove all whitespace around each part
val cols = line.split(",").map(_.trim)
// define parts
val sepal_len = cols.head.toDouble
val sepal_width = cols(1).toDouble
val petal_len = cols(2).toDouble
val petal_width = cols(3).toDouble
val species = if(cols.length == 6) cols(5) else cols(4)
// if sepal_area is defined
if (cols.length == 6) Iris(sepal_len, sepal_width, petal_len, petal_width, cols(4).toDouble, species)
// if sepal_area is not defined
else Iris(sepal_len, sepal_width, petal_len, petal_width, species = species)
}.toSeq
seq.foreach(println)
// Iris(1.0,5.1,3.5,1.4,5.1,Iris-setosa)
// Iris(2.0,4.9,3.0,1.4,9.8,Iris-setosa)
// Iris(3.0,4.7,3.2,1.3,14.1,Iris-setosa)
// Iris(4.0,4.6,3.1,1.5,18.4,Iris-setosa)
// Iris(5.0,5.0,3.6,1.4,25.0,Iris-setosa)
// Iris(6.0,5.4,3.9,1.7,32.4,Iris-setosa)
val newSeq = seq.toSeq
newSeq.foreach(println)
// close the source once you've finished with it
bufferedSource.close
}
Assume below are directory structures in a list, how to find lowest common ancestor for these.
List(
("A/A1/A11/A111/a111.txt", "(M)"),
("A/A1/A11/A112/a112.txt", "(M)"),
("A/A1/A12/A121/", "(D)")
)
Below function helped!!
def longestCommonParent(s1: String, s2: String): String = {
val maxSize = scala.math.min(s1.length, s2.length)
var i: Int = 0;
while (i < maxSize && s1(i) == s2(i)) i += 1;
parentFolder(s1.take(i));
}
def parentFolder(path: String) = {
path.substring(0, path.lastIndexOf("/"))
}
I am working on Scala to convert list of lists to list of customized object "Point"
class Point(val x: Int, val y: Int) {
var cX: Int = x
var cY: Int = y
}
Should I use Foreach or should I use Map or foreach in this case
def list_To_Point(_listOfPoints :List[List[String]]) : List[Point] = {
var elem =
lazy val _list: List[Point] = _listOfPoints.map(p=> new Point(p[0],p[1])
_list
}
I couldn't figure out where the problem exactly ?
def listToPoint(l:List[List[String]]):List[Point] =
l.collect({case x::y::Nil => new Point(x.toInt,y.toInt)})
But you really shouldn't use a List[String] to represent what is basically (Int,Int) …
ugly as hell and untested but it should work (pls consider making your structures immutable) :
case class Point(x:Int,y:Int)
object Point {
def listToPoint(listOfPoints:List[List[String]]):List[Point] =
listOfPoints.map(p => new Point(p(0).toInt,p(1).toInt))
}
A following C code uses enum and array as efficient "map" from enum to anything:
enum Color { ColorRed, ColorGreen, ColorBlue, ColorSize};
void f() {
int x[ColorSize];
x[ColorRed] = 12;
x[ColorGreen] = 33;
x[ColorBlue] = 4;
return x[ColorGreen];
}
Is this possible with Scala?
I.e. to have a "map" from case class to something, implemented as efficient array and not as tree or as hashmap. Yet I would like to be able to index only with a paricular type not with Int.
Update: In short I would like to have Scala Array indexed by some kind of enum (case class or Enumeration).
For small enumerations you can "simulate" the C behavior:
abstract sealed class Color(val index: Int)
object Color {
implicit def col2int(color:Color) = color.index
}
case object ColorRed extends Color(0)
case object ColorGreen extends Color(1)
case object ColorBlue extends Color(2)
...
import Color._
val array = Array(1,2,3)
array(ColorRed) = 12
However, I doubt this would be considered good style, especially because it's unsafe. Using a map is a better approach, or you could wrap an array in a specialized data structure which deals with Color indizes:
class ColorArray[T:ClassManifest] {
val array = new Array[T] (3)
def apply(color: Color) = array(color.index)
def update(color: Color, value: T) = array(color.index) = value
}
...
val cArray = new ColorArray[Int]()
cArray(ColorRed) = 12
println(cArray(ColorRed))
object Color extends Enumeration{
val ColorRed, ColorGreen, ColorBlue = Value
}
import Color._
def f:Map[Color.Value,Int] =
Map(ColorRed -> 12 , ColorGreen -> 33, ColorBlue -> 4)
If you want the full C performance you could do this:
trait CEnum {
private var size = 0;
def value = { size += 1; size-1 }
}
object Color extends CEnum {
val colorRed = value
val colorGreen = value
val colorBlue = value
val colorSize = 3
}
import Color._
def f() = {
val x = Array[Int](colorSize)
x(colorRed) = 12
x(colorGreen) = 33
x(colorBlue) = 4
x(colorGreen)
}
It's equally unsafe as the method in C & just as performant. It is however very unsafe.