如何定义可以是Array或List的变量

时间:2013-06-18 19:58:18

标签: scala scala-collections

可能是一个菜鸟问题,但我想在一个简短的脚本中做这样的事情:

val s = if ( <some condition> ) Array(...) else List(...)
print(s.length)

因为ObjectArray没有共同的超类,所以s将被推断为List。因此,第二行会出现错误,因为Object没有length方法。

提前致谢!

更新

呸,很遗憾我不能接受多个答案!谢谢你的帮助,伙计们!我和斯卡拉玩了很长一段时间,但似乎我还有很多需要学习的东西: - )

3 个答案:

答案 0 :(得分:4)

您可以使用Array的包装,并使用s作为Seq[T]

scala> val s = if (true) Array(1): Seq[Int] else List(1)
s: Seq[Int] = WrappedArray(1)

对于多维数组,您可以像这样创建自己的转换器:

implicit class ArrArrWrap[T](a: Array[Array[T]]) extends IndexedSeq[WrappedArray[T]] {
  def length = a.length
  def apply(idx: Int) = a(idx): WrappedArray[T]
}

用法:

scala> val s = if (true) Array(Array(1)): Seq[Seq[Int]] else List(List(1))
s: Seq[Seq[Int]] = (WrappedArray(1))

将多维数组用作多维序列的想法有一个很大的缺点:

它涉及对除最后一个维度以外的每个维度的访问权限的转换。

s(0) // <- conversion here

因此可能会导致性能问题。将Array转换为Seq

可能会更好
scala> val s = if (true) Array(Array(1)).map{ i => i: Seq[Int] }(breakOut) else List(List(1))
s: scala.collection.immutable.Seq[Seq[Int]] = Vector(WrappedArray(1))

答案 1 :(得分:2)

我认为Scala Iterable特性涵盖了这个用例:http://www.scala-lang.org/api/current/index.html#scala.collection.Iterable 我对Scala也很吵。

答案 2 :(得分:1)

您可以使用数组隐式转换为ArrayOps的事实,这使得它们可用作标准集合。基本上你需要做的就是选择ArrayOpsList共有的合适接口,并将其声明为变量的显式类型以触发转换:

val s: collection.SeqLike[Int,_] =
  if (condition) Array(1, 2, 3)
  else List(1, 2, 3, 4);
print(s.size)

更新:对于多维数组,您还需要在内部触发隐式转换,因为Array[ArrayOps[X]]无法分配给Array[Array[X]],反之亦然:< / p>

type SL[+A] = SeqLike[A,_]
val s1: SL[SL[Int]] =
  if (x) Array(Array(1, 2, 3): SL[Int]) else List(List(1, 2, 3, 4));
print(s1.size)

列表不需要它,因为它们的类型参数是协变的,因此当它们的一个超级接口使用时,它们可以在任何地方使用。

如果您是从一组固定的元素自己创建数组,则可以创建辅助函数,返回两个可能的包装器之一(ArrayOpsWrappedArray)。然后你不需要任何明确的输入:

import scala.collection.mutable._
import scala.reflect.ClassManifest

// Using ArrayOps
def arrayO[A: ClassManifest](xs: A*): ArrayOps[A] = Array(xs : _*);
val s2 =
  if (x) arrayO(arrayO(1, 2), arrayO(3)) else List(List(1, 2), List(3, 4));
println(s2.size)

// UsingWrappedArray
def arrayW[A: ClassManifest](xs: A*): WrappedArray[A] = Array(xs : _*);
val s3 =
  if (x) arrayW(arrayW(1, 2), arrayW(3)) else List(List(1, 2), List(3, 4));
println(s3.size)

如果您要包装现有数组,则需要像

一样包装每个级别
val a4 = Array(Array(1, 2, 3), Array(5, 6));
val s4: SL[SL[Int]] = a.map(x => x: SL[Int])