2

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

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

问题是 s 将被推断为因为和Object没有共同的超类。因此第二行给出了一个错误,因为没有方法。ArrayListObjectlength

提前致谢!

更新

呸,很遗憾我不能接受多个答案!感谢您的所有帮助,伙计们!我在 Scala 上玩了很长一段时间,但似乎我还有很多东西要学:-)

4

3 回答 3

4

您可以使用 wrapperArraysas 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

所以它可能会导致性能问题。最好转换ArraySeq

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))
于 2013-06-18T20:31:37.840 回答
2

我的印象是 Scala Iterable 特征涵盖了这个用例: http ://www.scala-lang.org/api/current/index.html#scala.collection.Iterable 我对 Scala 也很陌生。

于 2013-06-18T20:17:10.987 回答
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]],反之亦然:

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])
于 2013-06-18T20:33:05.830 回答