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 ?

Mario Santini
  • 2,905
  • 2
  • 20
  • 27
GregA
  • 302
  • 2
  • 7

2 Answers2

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);
trincot
  • 317,000
  • 35
  • 244
  • 286
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));
user3297291
  • 22,592
  • 4
  • 29
  • 45