【问题标题】:Flatten array in Scala 2.8 when some elements are not arrays当某些元素不是数组时,Scala 2.8 中的展平数组
【发布时间】:2011-01-05 06:18:36
【问题描述】:

如果我有

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

【问题讨论】:

    标签: scala


    【解决方案1】:
    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]。准确的类型是“IntArray[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

    【讨论】:

    • 感谢您的解决方案。我收到上述未经检查的警告,因此我将采用 Anwar Rizal 建议的解决方案。
    • 有人可以建议一种方法来解决上述解决方案中的类型擦除警告吗?这就是我得到的:“警告:类型模式 Array[T] 中的抽象类型 T 未选中,因为它被擦除大小写 ar 消除:Array[T] => ar”
    • 感谢更新的解决方案。我希望会有一个更简单的解决方案。你能给我指出EitherView 的原始参考吗?
    【解决方案2】:

    类似于 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)
    

    【讨论】:

    • 如果示例是典型的,这将返回 Array[Int]:a.flatMap { case ar: Array[Int] => ar;案例 x: Int => List(x) }
    • 这样好多了。我永远无法理解 ClassManifest。在我的真实代码中,它是 Ints 和其他类型的混合体,所以 Array[Any] 是我正在寻找的。也感谢 thoredge 的解决方案。
    • 该代码将返回一个对象数组,因此您将对其进行装箱和拆箱,并且无法将其传递给需要 Array[Int] 的函数。我的解决方案返回一个整数数组,并且可以在其他情况下使用。你不需要把头绕在 ClassManifest 上。只需复制和粘贴
    • @IttayD:您的解决方案(使用 ClassManifest)收到“未经检查的警告”。这正常吗?
    猜你喜欢
    • 1970-01-01
    • 2022-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 2016-09-06
    • 2015-11-03
    相关资源
    最近更新 更多