循环2维关联数组的最有效方法是什么?

时间:2012-12-11 02:30:35

标签: javascript multidimensional-array matrix

我有一个二维关联数组,其中包含需要在html5画布中绘制的块的映射。

目前完成它需要大约28ms,这太多了(我每秒运行60次代码),我需要以某种方式更有效地运行矩阵。这是我的代码:

for(var x=0; x<Object.keys(matrix).length; x++){ // Run through cols
    col = Object.keys(matrix)[x];
    for(var y=0; y<matrix[col].length; y++){ // Run though rows
        row = Object.keys(matrix[col])[y];
        if(matrix[col][row] != '0'){
            drawRect(col,row,blockSize,blockSize);
            }
        }
    }

我希望它效率低下,可以纠正一些问题。如何最有效地循环二维阵列的总数?

5 个答案:

答案 0 :(得分:1)

必须使用double for循环来循环整个2-D数组。与尝试使用性能问题加速任何代码一样,第一步是弄清楚什么花费了最多的时间,并首先在问题的元素中进行优化。

可能的猜测是drawRect比循环中的任何问题花费更多时间,但如果你想加快其余的代码,你可以做这些事情:

  1. 缓存Object.keys(matrix)因此不会不断重新计算
  2. 缓存每个for循环的停止值,以便每次循环都不会重新计算
  3. 缓存列键,以便每次通过内循环都不会重新计算
  4. 缓存矩阵列
  5. 该代码如下所示:

    var keys = Object.keys(matrix);
    for(var x = 0, lenX = keys.length; x < lenX; x++) { // Run through cols
        col = keys[x];
        var colKeys = Object.keys(matrix[col]);
        var matrixCol = matrix[col];
        for(var y = 0, lenY = matrix[col].length; y < lenY; y++) { // Run though rows
            row = colKeys[y];
            matrixCol[row] != '0'){
                drawRect(col,row,blockSize,blockSize);
            }
        }
    }
    

答案 1 :(得分:1)

您应该首先看到花费最长时间的内容。我敢打赌,drawRect函数是最慢的。而不是绘制矩形尝试打印到控制台(或在屏幕上写),看看需要多少时间。 然后,您可以计算drawRect执行1次操作所需的量。我认为这可能是你的问题,drawRect绘制时间太长。

答案 2 :(得分:0)

试试这个。

for(var x=0, xlimit=Object.keys(matrix).length; x<xlimit; x++){ // Run through cols
    col = Object.keys(matrix)[x];
    for(var y=0, ylimit=matrix[col].length; y<ylimit; y++){ // Run though rows
        row = Object.keys(matrix[col])[y];
        if(matrix[col][row] != '0'){
            drawRect(col,row,blockSize,blockSize);
        }
    }
}

答案 3 :(得分:0)

您可以尝试这样做以减少循环中的评估

var m = Object.keys(matrix), mc, x = 0, xlen = m.length, col, mcol, y, ylen, row;
for(;x < xlen; x++) {
  col = m[x];
  mc = matrix[col];
  for(y = 0, ylen = mc.length; y < ylen; y++) {
    row = mc[y];
    if(mc[row] != '0') {
      drawRect(col, row, blockSize, blockSize);
    }
  }
}

这里的要点是减少对对象键的评估需求。不知道如何减少,因为我不知道功能在做什么。

答案 4 :(得分:0)

感谢一些建议缓存大量变量的答案,我将绘图从30ms移到20ms。

然而今天我设法通过删除Object.keys()来达到1ms,因为我知道键的范围我改变了x和lenX以预先选择范围。与y和lenY相同。加载时间几乎不随着矩阵的大小而缩放。 (我测试了一个大100倍的矩阵,它只开始花了2ms)。

minX = Math.floor(cameraPos.x/blockSize)*blockSize;
minY = Math.floor(cameraPos.y/blockSize)*blockSize;
maxX = minX+WIDTH+blockSize;
maxY = minY+HEIGHT+blockSize;
for(var col = minX; col < maxX; col+=blockSize) { // Run through cols
    for(var row = minY; row < maxY; row+=blockSize) { // Run though rows
        if(typeof matrix[col] !== "undefined" && typeof matrix[col][row] !== "undefined"){
            drawRect(xFix(col),yFix(row),blockSize,blockSize,blockColors[matrix[col][row]]);
        }
    }
}

虽然功能非常快,但它最终会开始缩放,删除所有缩放,理论上可以使游戏地图变得非常大我每次相机滚动一定距离时开始缓存地图(现在它是两次屏幕宽度但是可能更多)。由于要缓存的区域使用与此类似的功能进行过滤,因此几乎可以立即完成。

var cached = [];
function cacheMap() {
    if(cached['pos'] === undefined || cameraPos.x < cached['pos']['x']-WIDTH || cameraPos.x > cached['pos']['x']+WIDTH || cameraPos.y < cached['pos']['y']-HEIGHT || cameraPos.y > cached['pos']['y']+HEIGHT) {
        cached['map'] = filterMatrix(map,cameraPos.x-WIDTH-blockSize*5,cameraPos.y-HEIGHT-blockSize*5,WIDTH*3+blockSize*10,HEIGHT*3+blockSize*10);
        cached['pos'] = {'x':cameraPos.x,'y':cameraPos.y};
        console.log('cached map');
        }
    }