Scala Cast List of Any to list of Int - scala

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.

Related

Read a tuple from a file in 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.

Scala cast to generic type

I'm confused about the generic type. I expect that 2.asInstanceOf[A] is cast to the type A, meanwhile, it's cast to Int.
Besides that, the input is java.lang.Long whereas the output is a list of Int (according to the definition the input and the output should be the same type). Why is that?
def whatever[A](x: A): List[A] = {
val two = 2.asInstanceOf[A]
val l = List(1.asInstanceOf[A],2.asInstanceOf[A])
println(f"Input type inside the function for 15L: ${x.getClass}")
println(f"The class of two: ${two.getClass}, the value of two: $two")
println(f"The class of the first element of l: ${l.head.getClass}, first element value: ${l.head}")
l
}
println(f"Returned from whatever function: ${whatever(15L)}")
the outupt:
Input type inside the function for 15L: class java.lang.Long
The class of two: class java.lang.Integer, the value of two: 2
The class of the first element of l: class java.lang.Integer, first element value: 1
Returned from whatever function: List(1, 2)
a.asInstanceOf[B] means:
Dear compiler;
Please forget what you think the type of a is. I know better. I know that if a isn't actually type B then my program could blow up, but I'm really very smart and that's not going to happen.
Sincerely yours, Super Programmer
In other words val b:B = a.asInstanceOf[B] won't create a new variable of type B, it will create a new variable that will be treated as if it were type B. If the actual underlying type of a is compatible with type B then everything is fine. If a's real type is incompatible with B then things blow up.
Type erasure. For the purposes of type checking 2 is cast to A; but at a later compilation stage A is erased to Object, so your code becomes equivalent to
def whatever(x: Object): List[Object] = {
val two = 2.asInstanceOf[Object]
val l = List(1.asInstanceOf[Object],2.asInstanceOf[Object])
println(f"Input type inside the function for 15L: ${x.getClass}")
println(f"The class of two: ${two.getClass}, the value of two: $two")
println(f"The class of the first element of l: ${l.head.getClass}, first element value: ${l.head}")
l
}
2.asInstanceOf[Object] is a boxing operation returning a java.lang.Integer.
If you try to actually use the return value as a List[Long] you'll eventually get a ClassCastException, e.g.
val list = whatever(15L)
val x = list(0)
x will be inferred to be Long and a cast inserted to unbox the expected java.lang.Long.
The answer from #jwvh is on point. Here I'll only add a solution in case you want to fix the problem of safely converting an Int to an A in whatever, without knowing what A is. This is of course only possible if you provide a way to build a particular A from an Int. We can do this in using a type-class:
trait BuildableFromInt[+A] {
def fromInt(i: Int): A
}
Now you only have to implicitly provide BuildableFromInt for any type A you wish to use in whatever:
object BuildableFromInt {
implicit val longFromInt: BuildableFromInt[Long] = Long.box(_)
}
and now define whatever to only accept compliant types A:
def whatever[A : BuildableFromInt](x: A): List[A] = {
val two = implicitly[BuildableFromInt[A]].fromInt(2)
// Use two like any other "A"
// ...
}
Now whatever can be used with any type for which a BuildableFromInt is available.

Convert the value in an Option to another type

I'm trying to do something that seems like it should have a straight forward syntax/function in scala. I just don't know what that is. I'm trying to convert the contained value of an Option (if it is not None) to another type.
Simply I want to know what the code would be if I wanted to implement the following function
def myFunc(inVal:Option[Double]):Option[BigDecimal] = {
//Code I need goes here
}
Note: I am not actually implementing this function, it just is the clearest way for me to demonstrate what I need
def myFunc(inVal: Option[Double]): Option[BigDecimal] =
inVal map {d => d: BigDecimal}
In general if you want to transform value in container (Option, Seq, List, Try, Future, etc) you should use method map on this container.
Method map accepts lambda (function) as parameter and applies this function to all elements. map should not change the count of elements: map on Some will never return None.
You could use method BigDecimal.apply to convert Double to BigDecimal like this:
BigDecimal(1.1)
// res0: scala.math.BigDecimal = 1.1
But there is also an implicit conversion from Double to BigDecimal, so you could just specify desired type like this:
1.1: BigDecimal
// res0: scala.math.BigDecimal = 1.1
val bd: BigDecimal = 1.2
PS: type inference allows you to use d => d instead of d => d: BigDecimal here, but it will make your code very unclear.
def myFunc(inVal: Option[Double]): Option[BigDecimal] = inVal map { BigDecimal(_) }
or
def myFunc(inVal: Option[Double]): Option[BigDecimal] = inVal map { BigDecimal.apply }
It works because Option is a Functor (no monadic trick in this simple use case)
Extending #senia's and #Yann Moisan's answers, if you want to keep something wrapped inside Option[] while still supplying a default value during conversion phase (could be a requirement down-the-line in your framework), you can use this:
def myFunc(inVal: Option[Double]): Option[BigDecimal] = {
Some(inVal.map(BigDecimal(_)).getOrElse(BigDecimal(0.0)))
}
It would not only convert your Option[Double] into Option[BigDecimal] but also create a default BigDecimal (with value 0.0) in case the origin Option[Double] turns out to be null.

scala accessing a list object inside another list

I am trying to access a list object inside of another list with a specific type
val x = List ("item1" , "item2" , List ("a","b","c"))
val list_from_x :List [String]= x(2) // producing error
I need my list_from_x of type to be of List [String]
any idea how to I do such conversion ?
So x is of type List[Object]**, because you've used two different (otherwise unrelated) classes as elements of that list.
You'll be unable to access elements other than of type Any without a type cast:
val listFromX = x(2).asInstanceOf[List[String]]
This is not type-safe, so you'll want to check element types (x(2).isInstanceOf[List[_]]) or pattern matching.
** Use the REPL to verify this; though val x: List[Any] = List ("item1" , "item2" , List ("a,b,c")) works
HList to the rescue:
import shapeless._
import Nat._
val x = "item1" :: "item2" :: List("a,b,c") :: HNil
val list_from_x = x(_2)
list_from_x has the type List[String]
See the shapeless github page for more info.
As other answers have mentioned, a List can only hold elements of a certain type. For example, a List[String] can only hold Strings. If you put elements of mixed types into a List, then the parametrised type of the List will become the most specific type common to all the elements.
The most specific type common to String and List is Any. So in this example, x is of type List[Any]:
val x = List("item1" , "item2" , List ("a,b,c"))
HList can hold elements of different types and maintain each element's type.
Scala compiler will simply say you got Objects (or may be Any) inside list x. That's why. You have to cast the 3rd element into a List in order to assign into a List variable.
The issue is List is defined as List[+A] (source). Which means List takes a type parameter of co-variant type. (You can think of co-variance as type converting from narrow to broader. For ex: if Dog extends Animal and if you do Animal a = new Dog(), you have a Dog (narrow) converting to Animal (broader))
x is of type List[Object]. Doing
scala> val x = List ("item1" , "item2" , List ("a,b,c"))
x: List[Object] = List(item1, item2, List(a,b,c))
val list_from_x :List [String]= x(2)
is ultimately converting from List[Object] (broader) to List[String] (narrow). Which is contra-variant. Hence the compiler threw error because List is meant to be co-variant.
For ex: the below is completely valid. Thanks to co-variance:
scala> val x = List("hello")
x: List[String] = List(sdf)
scala> val o:List[Object] = x
o: List[Object] = List(sdf)
More about it here and here

Does Scala have syntax for 0- and 1-tuples?

scala> val two = (1,2)
two: (Int, Int) = (1,2)
scala> val one = (1,)
<console>:1: error: illegal start of simple expression
val one = (1,)
^
scala> val zero = ()
zero: Unit = ()
Is this:
val one = Tuple1(5)
really the most concise way to write a singleton tuple literal in Scala? And does Unit work like an empty tuple?
Does this inconsistency bother anyone else?
really the most concise way to write a singleton tuple literal in Scala?
Yes.
And does Unit work like an empty tuple?
No, since it does not implement Product.
Does this inconsistency bother anyone else?
Not me.
It really is the most concise way to write a tuple with an arity of 1.
In the comments above I see many references to "why Tuple1 is useful".
Tuples in Scala extend the Product trait, which lets you iterate over the tuple members.
One can implement a method that has a parameter of type Product, and in this case Tuple1 is the only generic way to iterate fixed size collections with multiple types without losing the type information.
There are other reasons for using Tuple1, but this is the most common use-case that I had.
I have never seen a single use of Tuple1. Nor can I imagine one.
In Python, where people do use it, tuples are fixed-size collections. Tuples in Scala are not collections, they are cartesian products of types. So, an Int x Int is a Tuple2[Int, Int], or (Int, Int) for short. Naturally, an Int is an Int, and no type is meaningless.
The previous answers have given a valid Tuple of 1 element.
For one of zero elements this code could work:
object tuple0 extends AnyRef with Product {
def productArity = 0
def productElement(n: Int) = throw new IllegalStateException("No element")
def canEqual(that: Any) = false
}