Arrays 如何编写一个在Scala中具有自定义索引范围的有效的类似数组的结构?

Arrays 如何编写一个在Scala中具有自定义索引范围的有效的类似数组的结构?,arrays,scala,scala-collections,Arrays,Scala,Scala Collections,我想要类似Pascal的变量索引数组的东西,用户在其中指定有效的索引范围。我希望第一个索引为10000,最后一个为20000,而不是将索引内容的默认选项设置为0到长度1 Scala非常灵活,我想做的事情肯定是可行的。然而,创建一个和其他集合相协调的数据结构将需要规程 一个“明显的”解决方案可能是简单地将大小指定为20000,并浪费前半部分内存,但这并不好。此外,还可以使地图结构在瞬间工作。但是HashMap所涉及的开销是我所描述的类似数组的结构的一个数量级 理想情况下,它不应该重复或改造现有的代

我想要类似Pascal的变量索引数组的东西,用户在其中指定有效的索引范围。我希望第一个索引为10000,最后一个为20000,而不是将索引内容的默认选项设置为0到长度1

Scala非常灵活,我想做的事情肯定是可行的。然而,创建一个和其他集合相协调的数据结构将需要规程

一个“明显的”解决方案可能是简单地将大小指定为20000,并浪费前半部分内存,但这并不好。此外,还可以使地图结构在瞬间工作。但是HashMap所涉及的开销是我所描述的类似数组的结构的一个数量级

理想情况下,它不应该重复或改造现有的代码,也不应该过于复杂,即使是在内部

作为我想要的一个例子,考虑一个数组,它具有从500到999的有效索引。我将我的类称为IndexedArray,以区别于Scala中使用的标准数组。另外,我将使用Scala中的传统范围来指定声明中的索引范围

为了使事情保持简单,我不需要我的数据结构有一个不同的步骤。所有索引都是连续的

var histogram = new IndexedArray[Int](500 to 999)
histogram(500) = 10  // "first" entry has value 10
histogram(999) += 1  // "last" entry has value 1
当然,这个问题可以通过简单地使用一个标准的Scala数组,并在每次访问时重新映射索引来解决。但这不是虫子的食谱吗?我想让数据结构对我的眼睛隐藏那个小细节


当然,我的数据结构是可变的,因为Scala中的标准数组是可变的;行为上的唯一区别是每次访问都会自动重新映射索引

事实证明,要获得至少一个现在可以像广告中所宣传的那样工作的基本结构并不难。我真的希望让我的类扩展Scala集合中已有的适当结构,以便不可见地与可变集合API的其余部分合并。然而,到目前为止我还没能做到这一点

然而,我的基本解决方案通过使用与标准Scala数组相同的语法来访问元素,显示了Scala的一些惊人之处

class IndexedArray[T: ClassTag](val range: Range)  {

  val size: Int = range.end - range.start + 1
  val start: Int = range.start
  val array = new Array[T](size)

  def apply(index: Int): T = array(index - start).asInstanceOf[T]

  lazy val elemTag: ClassTag[T] = ClassTag[T](array.getClass.getComponentType)

  def length: Int = array.length

  def update(index: Int, elem: T): Unit = array.update( index - start, elem )

}
现在可以使用上述语法实例化数据结构,并使用如下数据结构。(对于Scala新手,以下两行代码是等效的,并且做相同的事情。)

然后,我们可以使用这个结构

pascalLike(500) = 100          // Sets the first element to 100
pascalLike(500) += 1           // Adds 1 to the first element
pascalLike(501) -= 2           // Subtracts 2 from the second element
println(pascalLike(501))       // Prints "-2"
我不知道的是如何使这个结构与Scala collections API的其余部分“流动”。例如,我希望
zipWithIndex
index方法能够像人们对这样的数据结构所期望的那样,使用适合该结构的索引


现在,合并这个家伙的唯一方法是获取底层的
数组
成员,并希望Scala编译器允许隐式转换,从而与用户想要做的事情相协调,这并不能完全满足我最初的目标

我可能只是扩展
列表
类,并在每次对列表应用操作时偏移索引。例如,
MyList(12000)
只是变成了
List(12000-10000)
对于那些不熟悉Pascal的人来说,你能简单地描述一下“变量索引数组”的确切含义吗?仅仅从语法的角度看,它看起来像什么?此外,10k-20k范围是连续的(仅偏移量),还是可以有一个非1“跨距”@xbonez如果您想找到一个线性序列集合,它尽可能像不可变数组一样,那就是
List
。此外,您的数据结构应该是固定大小还是可变大小?在第一种情况下,包装一个
数组
并在每次访问时偏移索引对我来说已经足够好了。
var pascalLike = IndexedArray[Int](500 to 999) 
pascalLike(500) = 100          // Sets the first element to 100
pascalLike(500) += 1           // Adds 1 to the first element
pascalLike(501) -= 2           // Subtracts 2 from the second element
println(pascalLike(501))       // Prints "-2"