Flatten array in Scala 2.8 when some elements are not arrays
If I have
var a = Array(Array(1, 2), 3, Array(4,5,6))
and I want to convert this to
开发者_如何学GoArray(1, 2, 3, 4, 5, 6)
what is the easiest way to do it? There is a solution for lists given in this post but it does not work for arrays.
I also tried
def flatArray(a:Array[Any])= a.map(x => x match { case ar:Array[_] => ar; case _ => Array(x) } )
but the output is of type ArraySeq
and I am not able to see how to convert it to Array
def flatArray[T : ClassManifest](a:Array[Any]) =
a.flatMap{
case ar:Array[T] => ar
case x: T => Array(x)
}
I've tried also to use the #flatten method, but it fails on NPE.
Update: To answer Jus12's question:
def flatArray[T : Manifest](a:Array[Any]) =
a.flatMap{
case ar: Array[_] if ar.getClass.getComponentType == manifest[T].erasure => ar.asInstanceOf[Array[T]];
case x => Array(x.asInstanceOf[T])
}
Of course the whole solution is not type safe. The reason is to accommodate the compiler's type inference which infers Array(Array(1, 2), 3, Array(4,5,6))
as Array[Any]
. An accurate type is "an array of either Int
or Array[Int]
", but that is not possible. What is is to create an array of Either elements where each element is Either[Int, Array[Int]]
and work with that:
object EitherView {
type ||[A, B] = Either[A, B]
// convenience of definition functions
private def l[A,B](a: A): ||[A,B] = Left(a)
private def r[A,B](b: B): ||[A,B] = Right(b)
// implicit defs - stuttering-or
implicit def aToOr2[A,B](a: A): A || B = l(a)
implicit def bToOr2[A,B](b: B): A || B = r(b)
implicit def aToOr3[A,B,C](a: A): A || B || C = l(l(a))
implicit def bToOr3[A,B,C](b: B): A || B || C = l(r(b))
implicit def aToOr4[A,B,C,D](a: A): A || B || C || D = l(l(l(a)))
implicit def bToOr4[A,B,C,D](b: B): A || B || C || D = l(l(r(b)))
implicit def aToOr5[A,B,C,D,E](a: A): A || B || C || D || E = l(l(l(l(a))))
implicit def bToOr5[A,B,C,D,E](b: B): A || B || C || D || E = l(l(l(r(b))))
// more? ...
}
import EitherView._
type CompoundArray[T] = Array[T || Array[T]]
object CompoundArray {
def apply[T](elems: (T || Array[T])*) = elems.toArray
}
def flatArray[T : Manifest](a:CompoundArray[T]) = {
a.flatMap{
case Left(x) => Array(x)
case Right(x) => x
}
}
See:
scala> val a = CompoundArray[Int](Array(1, 2), 3, Array(4,5,6))
a: Array[EitherView.||[Int,Array[Int]]] = Array(Right([I@1364b53), Left(3), Right([I@18b62e0))
scala> flatArray(a)
res0: Array[Int] = Array(1, 2, 3, 4, 5, 6)
scala> flatArray(CompoundArray[String](Array("hi"), "bye"))
res4: Array[String] = Array(hi, bye)
scala> flatArray(CompoundArray[String](Array("hi"), 3))
<console>:13: error: type mismatch;
found : Int(3)
required: EitherView.||[String,Array[String]]
flatArray(CompoundArray[String](Array("hi"), 3))
^
Note: The original idea for EitherView is by @Mitch Blevins: http://cleverlytitled.blogspot.com/2009/03/disjoint-bounded-views-redux.html
Similar to IttayD, without ClassManifest, and has Array[Any] as result.
scala> a.flatMap{
| case ar: Array[_] => ar
| case x => List(x)
| }
res4: Array[Any] = Array(1, 2, 3, 4, 5, 6)
精彩评论