Reputation: 363
I have the following code which splits an array into an array of arrays before any element that satisfies the predicate p
. It type checks:
def splitBefore[T](a: Array[T], p: (T) => Boolean)
(implicit tct: ClassTag[T]): Array[Array[T]] =
a.foldLeft(Array[Array[T]](Array.empty[T])) {
(acc: Array[Array[T]], s: T) => if (p(s))
acc :+ Array(s)
else
acc.init :+ (acc.last :+ s)
}
It works fine when I call it with non-empty a
:
scala> splitBefore(Array("a", "BC", "d"), (s: String) => s.size > 1)
res1: Array[Array[String]] = Array(Array(a), Array(BC, d))
But when I call it with an empty array, I get a ClassCastException
:
scala> splitBefore(Array.empty[String], (s: String) => s.size > 1)
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [[Ljava.lang.String;
... 33 elided
When I hand-inline the call so there is no type parameterization, it works fine:
scala> Array().foldLeft(Array(Array.empty[String])) {
| (acc: Array[Array[String]], s: String) => if (s.size > 1)
| acc :+ Array(s)
| else
| acc.init :+ (acc.last :+ s)
| }
res1: Array[Array[String]] = Array(Array())
Any idea what's going on here? I'm using Scala 2.11.7.
Upvotes: 3
Views: 72
Reputation: 683
Looks like instantiating a nested array causes a bug - it crashes even on such a small example:
def instantiate[A](ununsed_arg: Array[T])(implicit tag: ClassTag[A]) =
Array[Array[A]](Array.empty[A])
As a quick workaround, you might use an ArrayBuilder to create an array:
def instantiate[T](a: Array[T])(implicit ctc: ClassTag[T]) = {
val builder = ArrayBuilder.make[Array[T]]
builder += Array.empty[T]
builder.result
}
Also please note that your snippet directly appends elements to an array, which is a bad idea because it has to create a new array with one more slot and copy an element. Looks like you should either use an ArrayBuilder
or ArrayBuffer
to do the processing or build your new data structure out of Lists and convert them to Arrays
at the end.
Upvotes: 2