获取数组的一部分而不创建新副本

9
我正在尝试寻找一种切片极大数组的解决方案/解决方法,而不创建新的副本。这是我的问题。
假设我有一个大小为1亿或更多的双精度/整数大数组。我在一个非常大的数组中存储表示不同事物的多个不同数组,以显著节省内存使用。因此,我有一个大小为1亿的单个数组,而不是每个大小为100的100万个数组。我存储索引(开始和停止)以跟踪我的数据。
我想要获取数千个大小为100的切片。如果我使用Arrays.copyOfRange()方法来获取切片,那么它会破坏将所有内容放入单个大数组的目的,因为每个切片都是新的副本,吃掉了内存。
我有一个遗留代码(多年来由许多人编写的超过100万行),用于处理自己的数据(这些数据是较小的数组)。修改现有代码以使用大数组中的索引(开始、结束)不可能。
如果我可以以某种方式返回原始数组,使得返回的数组是一个引用(或者假装是一个引用),其中索引0是原始大数组中的某个任意索引,那就太好了。
在C/C++中,我可以轻松地返回一个特定偏移量和长度的指针,调用代码可以使用它。
在Java中,我有哪些选择?
编辑:我查看了以下类似的问题,但它没有回答我的问题。 如何在Java中获取数组的子数组而不复制数据?

3
在Java中不可能对数组进行"切片"。 - Luiggi Mendoza
1
我知道的唯一可以给你一个切片的结构是TreeSetTreeMap,但我不确定它们是否适用于你的问题。 - Luiggi Mendoza
3
"我将许多代表不同事物的不同数组存储在一个非常大的数组中,以显著节省内存使用量。" -- 你认为这能节省多少内存? - parsifal
1
@SantoshTiwari - 存储引用的8个字节是无关紧要的,因为你无论如何都需要为每个切片都有一个引用。当你谈论400MB的数据(1百万个数组x 100个元素x 4字节/元素)时,12MB(1百万个数组的12字节头)似乎不是很大的开销。如果你看到了50%的内存减少,那么肯定还有其他问题。 - Ted Hopp
1
考虑到Java不允许像C一样指向任意内存块,而且您无法更改这个遗留代码以使用自己的数据结构,似乎您唯一的选择就是购买更多的内存。 - parsifal
显示剩余8条评论
4个回答

3
对于int值的数组,您可以将其包装在IntBuffer中。您还可以包装数组的一个片段。
int[] largeArray = . . .

// create a slice containing the elements 100 through 149 (50 elements):
IntBuffer slice = IntBuffer.wrap(largeArray, 100, 50);

切片会创建一个我需要的范围(IntBuffer.get())的新副本,这将失去它的意义。 - Santosh Tiwari
@SantoshTiwari - 我认为你评论了我的答案的过时版本。当您像所示那样包装数组的一部分时,不会复制任何数据。 - Ted Hopp
IntBuffer.wrap() 方法将返回一个 IntBuffer 对象,该对象不能传递给现有代码。如果我能将返回的缓冲区包装成 int[],这种方法可能会起作用。谢谢。 - Santosh Tiwari
好的,有一个array()方法可以返回由原始缓冲区支持的数组。这可能有效。我会研究这个选项。谢谢。 - Santosh Tiwari
1
@SantoshTiwari - array() 方法返回整个后备数组,而不是切片。您需要使用 get(int[] dest) 方法来检索仅为切片的数组。在Java中,int[] 不能是另一个 int[] 的一部分的别名。 - Ted Hopp
是的,我已经尝试过了。IntBuffer 在我的情况下没有帮助。 - Santosh Tiwari

2
如何创建一个包装类,该类持有对原始数组和起始索引的引用,并使用该包装类的实例来访问原始数组。下面的代码可能在语法上不正确,但它应该能给你一个想法。
public class ArraySlice(){
  private int startIndex;
  private int[] originalArray;
  //getters-setters

  public ArraySlice(int[] originalArray, int startIndex){
    //Initialize
  }

  public int get(int index){
    return originalArray[startIndex+index]
  }
}

1
我们的答案几乎是完全一样的 :) 同时编写。我觉得有些有趣 :) - zubergu
1
完全同意我的想法 :) - Erkan Haspulat

1
你能创建一个自己的对象,用于存储索引、大小和原始数组的引用吗?
class CustomizedArray {
  int startIndex;
  int size;
  int[] originalArray;

  public CustomizedArray(int startIndex, int size, int[] originalArray) {
    this.startIndex = startIndex;
    this.size = size;
    this.originalArray = originalArray;
   }

   public int getIndex(int index) {
     int originalIndex = startIndex+index;
     if(index <0 || originalIndex >= startIndex+size) {
        throw new IndexOutOfBoundException();
     }
     return originalArray[originalIndex];


}

然后,您可以将CustomizedArray存储在某个更大的结构中。

1
你的最佳选择是将切片的索引存储在单独的数据结构中,例如存储这些索引的数组。
这样,您就不需要实例化整个数据数组的分区所包含的大型数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接