Zechariah Schneider Zechariah Schneider - 29 days ago 16
Java Question

Java Multi-Dimensional Array Indexing

I'm trying to represent an arbitrarily dimensioned matrix in Java as a 1d array and I'm struggling with the implementation the function I'm writing to calculate the correct index in the array given the location in the matrix. Here's what I have so far:

private int indexOf(int... indices) {
assert indices.length == rank() :
"Number of indices does not match rank";
if(indices.length == 1) return indices[0];
int x = 0;
for(int i = 1; i < indices.length; ++i){
x += indices[i] % this.dims[i];
}
return x;
}


Where rank() returns the number of dimensions in the matrix and this.dims is an array with the size of each dimension.

I know i=y*numCols + x works for the 2-d version but I'm just having trouble abstracting out to a matrix with variable dimensions.

Thanks for the help.

Answer

Sorry, I answer for my own pleasure (in JavaScript - runnable in Chrome Dev tools):

function SuperMatrix() {
  this.ranks = [].slice.call(arguments);
  this.rankCount = this.ranks.length;

  this.arraySize = 
    this.ranks.reduce(function(a,b) { return a*b; }, 1);

  this.dimensionSize = [];

  this.dimensionSize[this.rankCount-1] = 1;
  for (var i = this.rankCount-2; i >= 0; i -= 1) {
    this.dimensionSize[i] = 
      this.dimensionSize[i+1]*this.ranks[i+1];
  }

  this.array = new Array(this.arraySize);
}

SuperMatrix.prototype._index = function() {

  var indexes = [].slice.call(arguments);
  if (indexes.length !== this.rankCount)
     throw new Error('invalid number of indexes');

  var index = 0;
  for (var i = 0; i < this.rankCount; i += 1) {
    index += indexes[i]*this.dimensionSize[i];
  }

  if (index < 0 || index >= this.arraySize)
     throw new Error('invalid index: ' + indexes.join(', '));

  return index;
}

SuperMatrix.prototype.get = function() {
  var index = this._index.apply(this, arguments);
  return this.array[index];
};

SuperMatrix.prototype.set = function(value) {
  var indexes = [].slice.call(arguments, 1);

  var index = this._index.apply(this, indexes);
  this.array[index] = value;

  return value;
};


var foo = new SuperMatrix(2,3,5);

for (var i = 0; i < 2; i+=1) {
  for (var j =0; j < 3; j+=1) {
    for (var k = 0; k < 5; k+= 1) {
      foo.set([i,j,k].join(':'), i,j,k);
    }
  }
}

for (var i = 0; i < 2; i+=1) {
  for (var j =0; j < 3; j+=1) {
    for (var k = 0; k < 5; k+= 1) {
      console.log(foo.get(i,j,k));
    }
  }
}


console.log(foo);

For higher dimensional indexes: when index increases by 1 you must move in backing array by size of subarray.

Comments