2011-01-05 53 views
2

如果我有拼合陣列時,一些元素不是數組

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

,我想將其轉換爲

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

是什麼做的最簡單的方法?在this post 中給出了一個列表的解決方案,但它不適用於數組。

我也試過

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

但輸出ArraySeq型的,我不能看到如何將其轉換爲Array

回答

8
def flatArray[T : ClassManifest](a:Array[Any]) = 
    a.flatMap{ 
    case ar:Array[T] => ar 
    case x: T => Array(x) 
    } 

我試着也用#扁平化方法,但在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]。一個準確的類型是「一個IntArray[Int]」的數組,但這是不可能的。什麼是是,每個元素都是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([[email protected]), Left(3), Right([[email protected])) 

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最初的想法是由@米奇Blevins:http://cleverlytitled.blogspot.com/2009/03/disjoint-bounded-views-redux.html

+0

感謝您的解決方案。我得到了與上述的未經檢查的警告,所以我會去解決安瓦爾黎剎建議的解決方案。 – Jus12 2011-01-05 11:08:01

+0

有人可以提出一種解決上述解決方案中的類型擦除警告的方法嗎?這是我得到的:「警告:類型模式中的抽象類型T Array [T]未被選中,因爲它被擦除消除 case ar:Array [T] => ar」 – Jus12 2011-01-05 23:37:45

+0

感謝您的更新解決方案。我希望能有一個更簡單的解決方案。你能指出我對'EitherView'的原始參考嗎? – Jus12 2011-01-06 11:33:57

3

與IttayD類似,沒有ClassManifest,並且Array [Any]作爲結果。

scala> a.flatMap{ 
    |   case ar: Array[_] => ar 
    |   case x => List(x) 
    | } 
    res4: Array[Any] = Array(1, 2, 3, 4, 5, 6) 
+1

如果示例是典型的,這將返回Array [Int]: a.flatMap {case ar:Array [Int] => ar; case x:Int => List(x)} – thoredge 2011-01-05 08:34:48

+0

這樣好多了。我永遠無法繞過ClassManifest。在我的真實代碼中,它是Ints和其他類型的混合體,所以Array [Any]就是我一直在尋找的東西。感謝thoredge的解決方案。 – Jus12 2011-01-05 11:05:31

+0

該代碼將返回一個對象數組,因此您將使用裝箱和拆箱,並且無法將其傳遞給期望Array [Int]的函數。我的解決方案返回一個int數組,並可用於其他情況。你不需要在ClassManifest中包裹頭部。只需複製並粘貼 – IttayD 2011-01-05 13:44:47