Свести массив в Scala 2.8, когда некоторые элементы не являются массивами - PullRequest
2 голосов
/ 05 января 2011

Если у меня есть

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

и я хочу преобразовать это в

Array(1, 2, 3, 4, 5, 6)

, какой самый простой способ сделать это?Существует решение для списков, приведенных в этом посте , но оно не работает для массивов.

Я также пытался

def flatArray(a:Array[Any])= a.map(x => x match { case ar:Array[_] => ar; case _ => Array(x) } )

, но вывод имеет тип ArraySeq и я не могу увидеть, как преобразовать его в Array

Ответы [ 2 ]

8 голосов
/ 05 января 2011
def flatArray[T : ClassManifest](a:Array[Any]) = 
  a.flatMap{
    case ar:Array[T] => ar
    case x: T => Array(x) 
  }

Я также пытался использовать метод #flatten, но он не работает в NPE.

Обновление: чтобы ответить на вопрос Jus12:

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])
  }

Конечно, все решение небезопасно. Причина в том, чтобы учесть вывод типа компилятора, который выводит Array(Array(1, 2), 3, Array(4,5,6)) как Array[Any]. Точный тип - это «массив из Int или Array[Int]», но это невозможно. Что значит создать массив элементов Either, где каждый элемент равен Either[Int, Array[Int]], и работать с ним:

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
  }
}

См:

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))
                                                    ^

Примечание: оригинальная идея для EitherView - @Mitch Blevins: http://cleverlytitled.blogspot.com/2009/03/disjoint-bounded-views-redux.html

3 голосов
/ 05 января 2011

Аналогично IttayD, без ClassManifest и имеет в качестве результата массив [Любой].

    scala> a.flatMap{
     |          case ar: Array[_] => ar
     |          case x => List(x)
     | }
    res4: Array[Any] = Array(1, 2, 3, 4, 5, 6)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...