2

If I have

var a = Array(Array(1, 2), 3, Array(4,5,6))

and I want to convert this to

Array(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

2 Answers 2

8
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

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the solution. I get unchecked warnings with the above, so I will go with the solution suggested by Anwar Rizal.
Can someone suggest a way to work around the type erasure warning in the above solution? This is what I get: "warning: abstract type T in type pattern Array[T] is unchecked since it is eliminated by erasure case ar: Array[T] => ar"
Thanks for the updated solution. I was hoping there would be a more simpler solution. Can you point me to the original reference for EitherView?
3

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)

4 Comments

This will return Array[Int] if the example is typical: a.flatMap { case ar: Array[Int] => ar; case x: Int => List(x) }
This is much better. I can never get my head around ClassManifest. In my real code, it is a mixture of Ints and other types, so Array[Any] is what I was looking for. Thanks also for the solution by thoredge.
The code will return an array of objects, so you'll use boxing and unboxing with it and will not be able to pass it to functions that expect Array[Int]. My solution returns an array of ints, and can be used in other cases. You don't need to wrap your head around ClassManifest. Just copy & paste
@IttayD: I get an "unchecked warning" with your solution (using ClassManifest). Is that normal?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.