Java- Mapping multi-dimensional arrays to single

2019-09-01 09:01发布

问题:

I am posting this in relation to another open question i have, however I thought that this deserved it's own question.

Alternate question (for reference): Java Proxy Discovering Bot

Basically, I need to store a very large amount of data and have it accessible very quickly. This would work ideally in an unlimited memory situation:

boolean[][][][] sets = new boolean[256][256][256][256];
boolean get(byte[] a) {
    return sets[a[0]][a[1]][a[2]][a[3]];
}

However, this uses around 16gb of ram which is too much for my application. I figure that if using bits instead of booleans (stores as 4 bytes in Java) it would cut the memory usage to around 512MB. However, I can't seem to wrap my head around how to access the bits correctly. For example if you mapped each address something like this: position = a * b * c * d then it would map to the same bit as d * c * b * a etc.

I found this thread covering how to convert 2D arrays into 1D arrays, but I can't seem to wrap my head around how to extend that to a 4D array. Can anyone explain this? Map a 2D array onto a 1D array C

The solution for 2D -> 1D arrays:

int array[width * height];
int SetElement(int row, int col, int value)
{
  array[width * row + col] = value;  
}

I am just not sure of how to extend it to 4D -> 1D

 int array[256 * 256 * 256 * 256];
 int setElement(int a, int b, int c, int d, boolean value)
 {
    array[?????????] = value;  
 }

回答1:

To answer about mapping 4D to 1D, if you visualize, say, a chess board, you can come up with the formula for 2D to 1D by thinking if every row has width elements, and I first go down row number of rows and then move over to col, then I'm at width * row + col. Now imagine a stack of height number of chess boards and carry out the same exercise to extend it to three dimensions. Four dimensions is harder because you can't really visualize it, but by then you can see the pattern.

This program shows the formula for four dimensions. I ran it for very small numbers for posting here, but you can play with the dimensions and see how it works.

class Dim
{
    // dimensions
    static int d1 = 2 ;   // "rows"
    static int d2 = 2;    // "cols"
    static int d3 = 3;    // "height"
    static int d4 = 2;    // the fourth dimension!

    public static void main(String[] args) {
        for (int i=0; i<d1; i++) {
            for (int j=0; j<d2; j++) {
                for (int k=0; k<d3; k++) {
                    for (int m=0; m<d4; m++) {
                        int oneD = fourDtoOneD(i, j, k, m);
                        System.out.printf("(%d, %d, %d, %d) -> %d\n", i, j, k, m, oneD);
                    }
                }
            }
        }
    }

    static int fourDtoOneD(int i, int j, int k, int m) {
        return ((d2*d3*d4) * i) + ((d2*d3) * j) + (d2 * k) + m;
    }
}


$ java Dim
(0, 0, 0, 0) -> 0
(0, 0, 0, 1) -> 1
(0, 0, 1, 0) -> 2
(0, 0, 1, 1) -> 3
(0, 0, 2, 0) -> 4
(0, 0, 2, 1) -> 5
(0, 1, 0, 0) -> 6
(0, 1, 0, 1) -> 7
(0, 1, 1, 0) -> 8
(0, 1, 1, 1) -> 9
(0, 1, 2, 0) -> 10
(0, 1, 2, 1) -> 11
(1, 0, 0, 0) -> 12
(1, 0, 0, 1) -> 13
(1, 0, 1, 0) -> 14
(1, 0, 1, 1) -> 15
(1, 0, 2, 0) -> 16
(1, 0, 2, 1) -> 17
(1, 1, 0, 0) -> 18
(1, 1, 0, 1) -> 19
(1, 1, 1, 0) -> 20
(1, 1, 1, 1) -> 21
(1, 1, 2, 0) -> 22
(1, 1, 2, 1) -> 23