Jeffrey Benjamin Brown
Jeffrey Benjamin Brown

Reputation: 3709

Scala: Detect and extract something more specific from a collection of `Any` values

Scala: Detect and extract something more specific from a collection of Any values.

(Motivation: The Saddle library -- the only Scala library I have found that provides a Frame type, which is critical for data science -- leads me to this puzzle. See last section for details.)

The problem

Imagine a collection c of type C[Any]. Suppose that some of the elements of c are of a type T which is strictly more specific than Any.

I would like a way to find all the elements of type T, and to then create an object d of type C[T], rather than C[Any].

Some code demonstrating the problem

scala> val c  = List(0,1,"2","3")
<console>:11: warning: a type was inferred to be `Any`;
this may indicate a programming error.
       val c  = List(0,1,"2","3")
                ^
c: List[Any] = List(0, 1, 2, 3)

scala> :t c(0)
Any // I wish this were more specific

// Scala can convert some elements to Int.
scala> val c0 = c(0) . asInstanceOf[Int]
c0: Int = 0
// But how would I detect which?

scala> val d = c.slice(0,2)
d: List[Any] = List(0, 1) // I wish this were List[Int]

Motivation: Why the Saddle library leads me to this problem

Saddle lets you manipulate "Frames" (tables). Frames can have columns of various types. Some systems (e.g. Pandas) assign a separate type to each column. Every Frame in Saddle, however, has exactly three type parameters: The type of row labels, the type of column labels, and the type of cells.

Real world data is typically a mix of strings and numbers. The way such tables are represented in Saddle is as a Frame with a cell type of Any. I'd like to downcast (upcast? polymorphism is hard) a column to something more specific than a Series of Any values. I'd also like to be able to test a column, to be sure that the cast is appropriate.

I posted an issue on Saddle's Github site about the puzzle.

Upvotes: 0

Views: 61

Answers (1)

Lodewijk Bogaards
Lodewijk Bogaards

Reputation: 19987

You could do something like this

scala> val c  = List(0,1,"2","3")
c: List[Any] = List(0, 1, 2, 3)
scala> c.collect { case x: Int => x; case s: String => s.toInt  }
res0: List[Int] = List(0, 1, 2, 3)

If you just want the Int types you can simply drop the second case.

Upvotes: 1

Related Questions