1

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.

3
  • Are your dimensions always of equal size? In other words, is a 2D array always N x N and a 5D array N x N x N x N x N? Or can a 2D array be N x M? Commented Nov 6, 2016 at 16:27
  • The second case is true. Each dimension can be different sizes. Commented Nov 6, 2016 at 18:12
  • Why don't you actually insert arrays inside arrays, effectively creating a multidimensional array? The extra memory overhead for doing so would be negligible, and then the implementation becomes trivial. And you could do stuff like int value = arr[4][2][87][5] instead of int value = arr.indexof(4,2,87,5). Commented Nov 6, 2016 at 20:06

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Cool beans. Works perfectly! Thanks again

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.