Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating three dimensional Array with arbitrary type and map in Scala

When we have an Array of arbitrary type X in Scala and we try to do a double nest to each of its values using map (that is, turning [1,2,3] into [[[1]],[[2]],[[3]]]), we get a java.lang.ArrayStoreException. Code below is a minimal failing example:

import scala.reflect.ClassTag

def doubleNest[X: ClassTag](values: Array[X]): Array[Array[Array[X]]] = {
  values map { value =>
    Array(Array(value))
  }
}

doubleNest(Array(1,2,3))

What is more, error seems to arise when turning [[1],[2],[3]] into [[[1]],[[2]],[[3]]]. Code below is a minimal failing example (error happens in the second map):

import scala.reflect.ClassTag

def doubleNest[X: ClassTag](array: Array[X]): Array[Array[Array[X]]] = {
  val nested = array map { value =>
    Array(value)
  }

  nested map { arr =>
    Array(arr)
  }
}

doubleNest(Array(1,2,3))

Why does this happen?

like image 479
Nacho Cordón Avatar asked Jul 15 '26 09:07

Nacho Cordón


1 Answers

It seems that Scala doesn't like making nested generic arrays directly. Even this fails:

def foo[T: ClassTag](t: T) = Array(Array(t))
foo(1) // java.lang.ClassCastException: java.base/[Ljava.lang.Object; cannot be cast to [[I

(In this case, it's probably because ClassTag looks at the erased class, so Array.apply does the same, and it creates an Array[Array[Object]] instead of Array[Array[T]].)

It also appears that ClassTag has the methods wrap and newArray for this purpose. So, you can use some ugliness involving implicitly[ClassTag[X]].wrap.wrap.newArray(array.length) to get the job done, or you can do this, which seems to work by never directly asking it to create a nested array:

import scala.reflect.ClassTag

def nest[C: ClassTag](arr: Array[C]) = arr.map(Array(_))

def doubleNest[X: ClassTag](array: Array[X]): Array[Array[Array[X]]] =
  nest(nest(array))
like image 177
Brian McCutchon Avatar answered Jul 17 '26 23:07

Brian McCutchon