2

I wrote this method to transpose a javascript array

Array.prototype.transpose = function () {
   let rows = this.length;
   let cols = this[0].length;
   let ret = [[]];
   for (y=0;y<cols;y++)
     for (x=0;x<rows;x++)
       ret[y][x]=this[x][y]
   return ret;
}

However, this is very inefficient, since it actually copies the entire data.

What I prefer to do is to use a flag transposed? that would regard arr[x][y] as arr[y][x] if its turned on.

And then, the function transpose would just toggle it.

How can this be done in javascript ?

2
  • Java is not JavaScript. Commented Nov 2, 2016 at 12:45
  • I know, typo... now corrected Commented Nov 2, 2016 at 12:52

2 Answers 2

5

An alternative might be to use proxies. They allow you to capture object member access -- such as array bracket references -- and to return a customised value.

Here is a simple implementation that only supports get access to indices, and the length property, but nothing else. If you really wanted to, you could extend it to also support iteration, enumeration, setting, array methods (like join, map, ...), ...etc, but if you would go that far, and would really use these kinds of methods, then the question really becomes whether it is worth all the effort, as the total performance may be better if you do just like you did: copy the array into its transposed counter part.

Anyway, here it is:

var a = [ [1,2,3],
          [4,5,6] ];

a.transposed = new Proxy(a, {
    get: (arr, col) =>
        +col >= 0 ? new Proxy({ length: a.length }, {
                        get: (obj, row) => +row >=0 ? arr[row][col] : obj[row]
                    })
        : col == 'length'   ? arr[0] && arr[0].length
        : col == 'original' ? arr 
        : undefined
});

var t = a.transposed;
// Mutate a, to demo that also t shows the mutation:
a[0][2] = 3.5;
console.log('a = ', JSON.stringify(a));

console.log('a[0][2] = ', a[0][2], ', t[2][0] = ', t[2][0]);
console.log('a[0].length = ', a[0].length, ', t.length = ', t.length);
console.log('a.length = ', a.length, ', t[0].length = ', t[0].length);

// you can revert back to original array from the transposed one:
console.log('a === t.original?', a === t.original);

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

1 Comment

Yay for proxies! Browser support isn't quite there yet, though: caniuse.com/#feat=proxy
1

I don't think you can override the [] of an array, and I also believe it would introduce many nasty bugs if you could.

A quick solution might be to write a utility function that swaps the arguments:

var arr = [
  ['A', 'B', 'C'],
  [1, 2, 3],
  ['x', 'y', 'z']
];

// Using a short, pure function:
var getVal = (arr, i, j) => arr[i][j];
var getTransposed = (arr, i, j) => getVal(arr, j, i);

console.log(getVal(arr, 1,2));
console.log(getTransposed(arr, 1,2));

// Using a "class"
var Transposer = function(arr) {
  var myArr = arr.slice();
  var transposed = false;
  
  return {
    toggle: () => transposed = !transposed,
    isTransposed: () => transposed,
    getVal: (i, j) => transposed ? myArr[j][i] : myArr[i][j]
  }
};

var wrapped = Transposer(arr);

console.log(wrapped.getVal(1,2));
wrapped.toggle();
console.log(wrapped.getVal(1,2));

Comments

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.