有效地转置javascript数组

时间:2016-11-02 12:40:44

标签: javascript arrays matrix prototype

我写了这个方法来转置一个javascript数组

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;
}

然而,这是非常低效的,因为它实际上复制了整个数据。

我更喜欢使用标记为transposed?的标记arr[x][y]如果已启用arr[y][x]

然后,函数transpose只会切换它。

如何在javascript中完成?

2 个答案:

答案 0 :(得分:4)

替代方案可能是使用proxies。它们允许您捕获对象成员访问权限(例如数组括号引用)并返回自定义值。

这是一个简单的实现,只支持get访问索引和length属性,但没有别的。如果你真的想,你可以扩展它以支持迭代,枚举,设置,数组方法(如joinmap,...),...等,但如果你愿意的话到目前为止,并且真的会使用这些方法,那么问题确实变得是否值得所有的努力,因为如果你像你那样做总体性能可能会更好:将数组复制到其转置的计数器部分。 / p>

无论如何,这是:

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);

答案 1 :(得分:1)

我不认为你可以覆盖数组的[],我也相信如果可能的话会引入许多讨厌的错误。

快速解决方案可能是编写一个交换参数的实用程序函数:

&#13;
&#13;
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));
&#13;
&#13;
&#13;