如何在javascript中快速缩放二维数组?

时间:2018-04-02 23:40:26

标签: javascript arrays algorithm matrix

给定二维数组a:

let a = [
    [0, 0, 1, 0], 
    [0, 1, 1, 1], 
    [0, 0, 1, 0], 
    [0, 0, 1, 1] 
]

我如何按给定因子进行缩放?例如,数组b是按4缩放的数组:

let b =[ 
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]
]

这是我为执行此操作而编写的代码,但在处理大型数组(200 x 200)时速度很慢(客户端浏览器:Chrome),而缩放比例可以说是16。

// scale an array by a factor of 'scale'

const scaledMatrixArray = (arr, scale) => {
        let newArr = [];
        arr.forEach((el) => {
            let newArrRow = [];
            el.forEach((el) => {
                for (let j = 0; j < scale; j++) {
                    newArrRow.push(el);
                }
            });
            for(let i = 0; i < scale ; i++) {
                newArr.push(newArrRow);
            }
        });
        return newArr;
    };

我理解我的实现是O(n ^ 2)的一些变体,效率很低。我正在寻找一种更好的方法来做到这一点,或者是一个更好更快地完成它的库。我的最终结果是我的 N X N 数组超过N&gt; 200可以以最有效,最快和最少内存密集的方式扩展到800 x 800的阵列。

4 个答案:

答案 0 :(得分:4)

这是一种非常简化的方式,使用Array().fill,至少在我的浏览器中运行速度比其他答案快。

我添加了两个版本,一个使用spread运算符,另一个使用.apply。我使用apply获得了更快的结果。

function scaleSpread(array, factor) {
	const scaled = [];

	for(const row of array) {
		let x = [];

		for(const item of row)
			x.push(...Array(factor).fill(item));

		scaled.push(...Array(factor).fill(x));
	}

	return scaled;
}

function scaleApply(array, factor) {
	const scaled = [];

	for(const row of array) {
		let x = [];

		for(const item of row)
			x.push.apply(x, Array(factor).fill(item));

		scaled.push.apply(scaled, Array(factor).fill(x));
	}

	return scaled;
}

function scaleConcat(array, factor) {
	let scaled = [];

	for(const row of array) {
		let x = [];

		for(const item of row)
			x = x.concat(Array(factor).fill(item));

		scaled = scaled.concat(Array(factor).fill(x));
	}

	return scaled;
}

var a = [ [0, 0, 1, 0], [0, 1, 1, 1],  [0, 0, 1, 0],  [0, 0, 1, 1] ]

console.time('spread');
scaleSpread(a, 10000);
console.timeEnd('spread');

console.time('apply');
scaleApply(a, 10000);
console.timeEnd('apply');

console.time('concat');
scaleConcat(a, 10000);
console.timeEnd('concat');

编辑:使用.concat添加了版本,因为应用和传播导致Maximum call stack size exceeded包含非常大的数组。

答案 1 :(得分:3)

这种方法使用for loop来迭代一个n维数组,用于决定n次。

这使用Array.splice方法,通过获取源值并将其插入到某个索引处的数组中。

PS:源数组(a)在此变异。但是,您可以随时克隆原始数组,并根据需要为结果创建b

&#13;
&#13;
var a = [
    [0, 0, 1, 0],
    [0, 1, 1, 1], 
    [0, 0, 1, 0], 
    [0, 0, 1, 1] 
  ],
  scale = 4,
  scaleTheArray = function (arrayToScale, nTimes) {
    for (var idx = 0, i = 0, len = arrayToScale.length * nTimes; i < len; i++) {
      var elem = arrayToScale[idx];

      /* Insert the element into (idx + 1) */
      arrayToScale.splice(idx + 1, 0, elem);

      /* Add idx for the next elements */
      if ((i + 1) % nTimes === 0) {
        idx += nTimes + 1;
      }
    }
  };

console.time('testScale');

/* 1. Expand each of the a[n] length */
for (var i = 0, len = a.length; i < len; i++) {
  var arr = a[i];

  scaleTheArray(arr, scale - 1);
}

/* 2. Expand each of the a length */
scaleTheArray(a, scale - 1);

console.timeEnd('testScale');
&#13;
&#13;
&#13;

答案 2 :(得分:3)

通常,较少的函数调用=较少的开销:

&#13;
&#13;
function scale1D(arr, n) 
{
  for (var i = arr.length *= n; i; ) 
    arr[--i] = arr[i / n | 0]
}

function scale2D(arr, n) 
{
  for (var i = arr.length; i; )
    scale1D(arr[--i], n)

  scale1D(arr, n)
}

var a = [ [0, 0, 1, 0], [0, 1, 1, 1],  [0, 0, 1, 0],  [0, 0, 1, 1] ]
console.time( 1e6 )
scale2D(a, 1e6)
console.timeEnd( 1e6 )

var b = [ [0, 0, 1, 0], [0, 1, 1, 1],  [0, 0, 1, 0],  [0, 0, 1, 1] ]
scale2D(b, 4)
console.log( JSON.stringify( b ).replace(/],/g, '],\n ') )
&#13;
&#13;
&#13;

答案 3 :(得分:2)

有点乐趣,如果你没有访问很多值,你可以懒得去做。没有对这段代码进行过多次测试,但是应该可以使用

        var a = [
            [0, 0, 1, 0],
            [0, 1, 1, 1], 
            [0, 0, 1, 0], 
            [0, 0, 1, 42] 
          ],
          scale = 4;
    
        for (var idx = 0; idx < a.length; idx++) {
            a[idx] = new Proxy(a[idx], {
              get: function(target, i) {
            return target[Math.floor(i/scale)];
          }
        });
        }
        a = new Proxy(a, {
              get: function(target, i) {
            return target[Math.floor(i/scale)];
          }
        });
    
        console.log(a[16-1][16-1])

        for (var ii = 0; ii < 16;ii++) {
          for(var j=0;j<16;j++){
            console.log(a[ii][j])
          }
        }