Read a tuple from a file in Scala - scala

my Task is to read registrations from a file given like:
Keri,345246,2
Ingar,488058,2
Almeta,422016,1
and insert them into a list(Tuple of (String, Int, Int).
So far I wrote this:
The problem is that I don‘t understand why I can't try to cast value2 and value3 to Int even tho they should be Strings because they come from an Array of Strings. Could someone tell me, what my mistake is, I am relatively new to Scala

What is the point of using Scala if you are going to write Java code?
This is how you would properly read a file as a List of case classes.
import scala.io.Source
import scala.util.Using
// Use proper names for the fields.
final case class Registration(field1: String, field2: Int, field3: Int)
// You may change the error handling logic.
def readRegistrationsFromFile(fileName: String): List[Registration] =
Using(Source.fromFile(fileName)) { source =>
source.getLines().map(line => line.split(',').toList).flatMap {
case field1Raw :: field2Raw :: field3Raw :: Nil =>
for {
field2 <- field2Raw.toIntOption
field3 <- field3Raw.toIntOption
} yield Registration(field1 = field1Raw.trim, field2, field3)
case _ =>
None
}.toList
}.getOrElse(default = List.empty)
(feel free to ask any question you may have about this code)

In Scala, in order to convert a String to an Int you need explicit casting.
This can be achieved like this if you are sure the string can be parsed into a integer:
val values = values(1).toInt
If you cannot trust the input (and you probably should not), you can use .toIntOption which will give you a Option[Int] defined if the value was converted successfully or undefined if the string did not represent an integer.

The previous answers are correct. I would add a few more points.
saveContent is declared as a val. This is means it cannot be changed (assigned another value). You can use the Scala REPL (command-line) tool to check:
scala> val saveContent = Nil
val v: collection.immutable.Nil.type = List()
scala> saveContent = 3
^
error: reassignment to val
Instead, you could use a var, although it would be more idiomatic to have an overall pattern like the one provided by Luis Miguel's answer - with pattern-matching and a for-comprehension.
You can use the Scala REPL to check the types of the variables, too. Splitting a String will always lead to more Strings, not Ints, etc.
> val values = "a,2,3".split(",")
val values: Array[String] = Array(a, 2, 3)
> values(2)
val res3: String = 3
This is why a cast like Gael's is necessary.
Array-type access is done with parentheses and not square brackets, in Scala. See above, and http://scalatutorials.com/tour/interactive_tour_of_scala_lists for more details.

Related

How can I cast a a string to generic number using scala?

I'm trying to convert a generic string to a number using scala
object h extends App {
def castTo[T](s: String): T = {
s.asInstanceOf[T]
}
print(castTo[Int]("20"))
print(castTo[Double]("20.1"))
}
the data:
name | value
a | "1"
b | "2.123"
c | "abd"
the usecase:
riight now I'm exporting the data to the user a method for each conversion.
getNameAsDouble, getNameAsInteger and so forth.
I wish to do getNameT to save lot's of code and make it a bit more pretty and easy to read the doc.
so, in case a programmer does :
getNameInt i want the program to print in this case: 1
getNameDouble i want the program to print in this case: 2.123
in cpp i could use dynamic_cast. there a way to do so in scala?
( i also tried to do so in java but couldn't find a way)
p.s.
i've tried something like this, but i wandered if there is more generic way.
castTo[T] (s:String): T = {
...
case T instance of Integer => s.toInt
case T instance of Long => s.toLong
...
}
I believe it would be better if you can expand more on your use case.
But, this should do what you want.
def readAs[T](str: String)(implicit num: Numeric[T]): Option[T] =
num.parseString(str)
Which you can test like:
readAs[Int]("10")
// res: Option[Int] = Some(10)
readAs[Double]("10")
// res: Option[Double] = Some(10.0)
readAs[Double]("10.0d")
// res: Option[Double] = Some(10.0)
readAs[Int]("10.0d")
// res: Option[Int] = None
readAs[Int]("blah")
// res: Option[Int] = None
Scala is not javascript. Scala is a real programming language with types. Strong types even. So, it treats conversions between types as what they really are: conversions. Not "casts". So, the string will have to be parsed into a number. And if you wrap this parsing in a function, it is utterly wrong to call this conversion a "cast".
And no, you cannot cast a string to a number in C++ either. Not with a dynamic cast, nor with any other kind of cast. You also have to parse it in C++, because C++ is also a real programming language.
As for simplifying your pattern matching expression, you might be able to first parse the string into a double, and then use a generic cast to convert that double into a number of lesser precision, but I do not have a Scala compiler at hand to prove the concept.

scala mutable.Map put/get handles null's in an unexpected way?

I know one is not supposed to use nulls in scala but sometimes when interoperating with Java it happens. The way a scala mutable map handles this seems off though:
scala> import scala.collection.mutable
import scala.collection.mutable
scala> val m: mutable.Map[String, String] = mutable.Map.empty
m: scala.collection.mutable.Map[String,String] = Map()
scala> m.put("Bogus", null)
res0: Option[String] = None
scala> m.get("Bogus")
res1: Option[String] = Some(null)
scala> m.getOrElse("Bogus", "default")
res2: String = null
I would have expected m.get to return None in this case. Almost seems like a bug, like somewhere in the code there was a Some(v) instead of Option(v)
Is there discussion w/r/t to changing this behavior?
I would have expected m.get to return None in this case.
Why? None would mean the key "Bogus" is not in the map, but you just put it in (with value null).
Java's Map API has problems distinguishing "the value for this key is null" from "this key is not in the map", but Scala's doesn't.
Null is subtype of String:
scala> implicitly[Null <:< String]
res3: Null <:< String = <function1>
Therefore null is a valid String value:
scala> val s: String = null
s: String = null
If you want to store a null as a String in a map, it's your good right.
Compared to Java's Map#get (let's call it javaLikeGet), the Scala's get behaves roughly as follows:
def get(k: K) = if (containsKey(k)) {
Some(this.javaLikeGet(k))
} else {
None
}
and not like what you have assumed:
def get(k: K) = Option(this.javaLikeGet(k))
The latter version (presumably what you thought) would get a null for an existing key, pass it to Option(...), and return None. But the former version (which imitates how the real implementation works) would notice that the key exists, and wrap the null returned by javaLikeGet into a Some.
The simple and consistent rule is:
If the key k exists, then get(k) returns Some[V], otherwise it returns None.
This is much less surprising than the strange behavior of Java's get that returns null in two entirely different situations.
This is the Billion-Dollar Mistake, but Scala is not the language that is likely to fix it, because it has to interop with Java. My guess is that there is and will be no discussion about changing this behavior, at least not until something fundamentally changes in the entire programming landscape.

Scala Cast List of Any to list of Int

Given a List of Any:
val l = List(2.9940714E7, 2.9931662E7, 2.993162E7, 2.9931625E7, 2.9930708E7, 2.9930708E7, 2.9931477E7)
I need to cast each item to Int.
Works:
l(1).asInstanceOf[Double].toInt
Not:
l.foreach{_.asInstanceOf[Double].toInt}
> java.lang.String cannot be cast to java.lang.Double
If
l.foreach{_.asInstanceOf[String].toDouble.toInt}
> java.lang.Double cannot be cast to java.lang.String
I'm new to Scala. Please tell me what I'm missing.
Why I can cast one item from list, but can't do this via iterator?
Thanks!
It seems as if a String somehow ended up in your List l.
Given a list that is structured like this (with mixed integers, Doubles, and Strings):
val l = List[Any](2.9940714E7, 2.9931625E7, "2.345E8", 345563)
You can convert it to list of integers as follows:
val lAsInts = l.map {
case i: Int => i
case d: Double => d.toInt
case s: String => s.toDouble.toInt
}
println(lAsInts)
This works for Doubles, Ints and Strings. If it still crashes with some exceptions during the cast, then you can add more cases. You can, of course, do the same in a foreach if you want, but in this case it wouldn't do anything, because you don't do anything in the body of foreach except casting. This has no useful side-effects (e.g. it prints nothing).
Another option would be:
lAsInts = l.map{_.toString.toDouble.toInt}
This is in a way even more forgiving to all kind of weird input, at least as long as all values are "numeric" in some sense.
However, this is definitely code-smell: how did you get a list with such a wild mix of values to begin with?
Your given List is of type Double. You can use simply map operation to convert it to Int type. try following code,
val l: List[Double] = List(2.9940714E7, 2.9931662E7, 2.993162E7, 2.9931625E7, 2.9930708E7, 2.9930708E7, 2.9931477E7)
//simply map the list and use toInt
val intLst: List[Int] = l.map(_.toInt)
print(intLst)
//output
//List(29940714, 29931662, 29931620, 29931625, 29930708, 29930708, 29931477)
But suppose you have same List as List[Any] instead then you can use following to convert it to Int.
val l: List[Any] = List(2.9940714E7, 2.9931662E7, 2.993162E7, 2.9931625E7, 2.9930708E7, 2.9930708E7, 2.9931477E7)
val intLst: List[Int] = l.map(_.asInstanceOf[Double].toInt)
It will give same output as above.

Get class fields by name

For example my case class is
case class Test(id: String, myValues: List[Item])
case class Item(id: Long, order: Long)
and I get string value like
val checkValue: String = "id"
I want sort Tests by items and I want it to look like
val test= Test("0", List(Item(0, 14), Item(1, 34))
val sortedItems = test.myValues.map(_.*checkValue*).sorted
Its about get field of class like someInstanceOfClass.checkValue
Scala is not an interpreted language, therefore you can't just use strings as variable names. The easiest way to solve your problem is to map the string value to the variable:
scala> def get(item: Items, str: String) = str match {
| case "id" => item.id
| case "order" => item.order
| }
get: (item: Items, str: String)Long
scala> test.myValues.map(get(_, checkValue)).sorted
res0: List[Long] = List(0, 1)
scala> test.myValues.map(get(_, "order")).sorted
res1: List[Long] = List(14, 34)
Of course there are more ways to solve the problem. You could use Reflection to read the name of the variable at runtime. In case you already know at compile time the name of the variable you want to read, you could also use macros to generate the code that is doing what you want. But these are both very specialized solutions, I would go with the runtime matching as shown above.
You may wish to rethink how you're going about this. What good does the string "id" actually do you? If you just need the capability to pull out a particular bit of data, why not use a function?
val f: Item => Long = _.id
Do you not want to have to type the function type over and over again? That's fine too; you can use a method to request the compiler's help filling in the type arguments:
def pick[A](x: Item => A) = x
val f = pick(_.id)
Now you can use f anywhere you would have used "id". (You can even name it id instead of f if that will help, or something that reminds you that it's actually a function that gets an id, not an id itself, like idF or getId.)

Scala Macros: Convert/parse a Tree to a Name

This is a simplified example but the problem remains the same.
I want to achieve this using macros (scala based pseudocode):
(a: Int) => {
val z = "toShort"
a.z
}
If I reify it, I would obtain something similar to this:
Function(
List(
ValDef(
Modifiers(Flag.PARAM),
newTermName("a"),
Ident(scala.Int),
EmptyTree
)
),
Block(
List(
ValDef(
Modifiers(),
newTermName("z"),
TypeTree(),
Literal(Constant("toShort"))
)
),
Apply(
Select(
Ident(newTermName("a")),
newTermName("toShort")
),
List()
)
)
)
I dont know how to access to a value and then use it as a TermName.
I tried replacing newTermName("toShort") with newTermName(c.Expr[String](Select(Ident(newTermName("z")))).splice) but the compiler doesn't seem to like:
exception during macro expansion:
java.lang.UnsupportedOperationException: the function you're calling has not been spliced by > the compiler.
this means there is a cross-stage evaluation involved, and it needs to be invoked explicitly.
if you're sure this is not an oversight, add scala-compiler.jar to the classpath,
import scala.tools.reflect.Eval and call <your expr>.eval instead.
I've also tried 'eval' as suggested by compiler: newTermName(c.eval(c.Expr[String](...)) but neither worked.
How could I convert a tree like Select(Ident(newTermName("z"))) (which is a access to a value of a local val) to a Name a string which can be used as a parameter for newTermName? Is it possible?
UPDATE:
Here the real problem brought to you as a gist!
Thanks in advance,
I have a hard time understanding what you're trying to achieve, and why you are using Trees everywhere. Trees are really low level, hard to use, tricky, and it is very difficult to understand what the code does. Quasiquotes (http://docs.scala-lang.org/overviews/macros/quasiquotes.html) are the way to go indeed and you can use them on scala 2.10.x production release thanks to the macro paradise plugin (http://docs.scala-lang.org/overviews/macros/paradise.html). The you can simply write q"(a: Int) => {val z = "toShort"; a.z}" and you directly get the tree expression you just typed.
To answer your question, the first point is to remember that macros are evaluated at compile time. They therefore can not generate code which depends on a runtime value. This is why the compiler is complaining about your splice. But if you pass a value which can be computed at compile time, typically a literal, then you can use eval to get its value within your macro code. Eval does suffer a bug though, as indicated in scaladoc. It should only be called on untyped trees. So the way to call eval on an s: c.Expr[String] expression would be val s2 = c.eval(c.Expr[String](c.resetAllAttrs(c.tree.duplicate))) which gives you a String you can then use normally in your code, for instance q"(a: Int) => a.${newTermName(s2)}".
To put it all together, let's imagine you to create a macro that'll output a string value from an object and one of its String field. It'll give something like
def attr[A](a: A, field: String): String = macro attrImpl[A]
def attrImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A], field: c.Expr[String]) = {
import c.universe._
val s = c.eval(c.Expr[String](c.resetAllAttrs(field.tree.duplicate)))
c.Expr[String](q"a.${newTermName(s)}")
}
REPL session test:
scala> object a { val field1 = "field1"; val field2 = "field2" }
defined module a
scala> attr(a, "field1")
res0: String = field1
scala> attr(a, "field2")
res1: String = field2
To understand the difference between compile time and runtime, you can meditate about the following result in REPL ;-)
scala> val s = "field1"; attr(a, s)
error: exception during macro expansion:
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
$iw is not an enclosing class
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.throwIfErrors(ToolBoxFactory.scala:311)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:244)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:408)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:411)
at scala.reflect.macros.runtime.Evals$class.eval(Evals.scala:16)
at scala.reflect.macros.runtime.Context.eval(Context.scala:6)
at .attrImpl(<console>:14)
scala> val s = "field1"
s: String = field1
scala> attr(a, s)
res3: String = field1
Hope it helps ;))