2012-12-11 87 views
0

我有一個包含地圖上需要在一個HTML5畫布要繪製的塊的二維數組。最有效的循環2維關聯數組的方式?

目前,它需要大約28ms來完成它,這實在是太多了(我運行代碼60次),我需要儘管矩陣更efficienty莫名其妙地運行。這是我的代碼:

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

我希望它效率低下,可以糾正一些問題。如何最有效地循環二維數組的總數?

回答

1

您必須使用double for循環來循環整個2-D數組。與試圖加快與性能問題的任何代碼,第一個步驟就是要弄清楚什麼是首先花費大部分時間和工作在你優化的問題該元素。

的可能的猜測是,drawRect中花費的時間比任何的循環問題的方式更多的時間,但如果你想加快代碼的其餘部分,你可以做這些事情:

  1. 緩存Object.keys(matrix)所以它不是不斷重新計算
  2. 緩存爲每個for循環停止值以便它不通過每個循環
  3. 高速緩存中的列密鑰重新計算每次以便它不通過內循環重新計算每次
  4. CAC他矩陣列

該代碼是這樣的:

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); 
     } 
    } 
} 
+0

那麼「matrix [col]」緩存呢? –

+1

@ kitgui.com - 我也加了一個。 – jfriend00

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

你應該首先看到需要的時間最長。我敢打賭,drawRect函數是最慢的一堆。而不是畫矩形試圖打印到控制檯(或寫在屏幕上),看看需要多少時間。 然後,您可以計算drawRect執行1次操作需要多少時間。我認爲這可能是你的問題,drawRect花費很長時間來繪製。

+0

+1用於建議配置文件以識別熱點/慢點。 –

+1

是的,drawRect()是clode中最慢的部分,但我認爲沒有辦法避開它。只要我優化循環,我會看看是否有一種方法來保存變量中的每個方塊位置並一次繪製所有方塊。也許這是可能的,我不太瞭解html5畫布 – lisovaccaro

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

主要的一點是這裏以減少對象鍵上的評價,需要內減少評估。不知道如何減少超過這一點,因爲我不知道這些功能在做什麼。

0

由於一些答案,暗示緩存很多變數我完成的繪圖採取30毫秒爲20ms去。

但是今天我設法去除Object.keys()得到它的1ms的和我知道的範圍內的按鍵將是我改變x和聯欣預選的範圍內。與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'); 
     } 
    } 
+0

嗯。你確定這就是你想要使用StackOverflow的方式嗎?將獲得的聲望點從幫助你的其他人那裏拿走,這樣你就可以爲自己的答案投票了?特別是當你的答案包括我們不可能知道的事情時(比如去掉Object.keys()),我明白你想如何分享你的最終答案(沒有什麼不對),但不知何故它似乎倒退了從最有幫助的答案中拿出聲望點,通過取消你之前的投票來獲得最佳答案 – jfriend00

+0

好的,我標記了你的答案,因爲它是最有幫助的,但我應該指出,我的真正問題是我正在循環整個對象,減少循環到一個小區域是真正造成差異的原因。 – lisovaccaro