2017-09-14 48 views
0

我想遍歷二維數組中的單元格的鄰居。所以我用:迭代2D數組的偏移量

for (int xOffset = -1; xOffset <= 1; xOffset++) { 
    for (int yOffset = -1; yOffset <= 1; yOffset++) { 
     if (xOffset == 0 && yOffset == 0) { 
      continue; 
     } 
     //My Code 
    } 
} 

我的問題是,如果這是最有效的方式還是更只使用,如果電話?如果有更好的方法比在循環內部使用它來擺脫零點零位的情況更好?

+0

你認爲什麼是最可讀性和可維護性的解決方案?這裏是否存在實際的性能問題? – tnw

+1

是的它是一種性能問題,我尋找所有我可以優化的東西。這是在數百萬個對象的更新循環中運行的。 – TheSorm

+0

因此,使用您當前的解決方案的性能是否存在實際問題? – tnw

回答

1

我通常使用以下方法:

int dirs[][] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; 

for (int dir[] : dirs) { 
    int xOffset = dir[0]; 
    int yOffset = dir[1]; 
    // my code 
} 
+0

確定會採用循環外的xOffset,yOffset聲明,但接受一件好事謝謝:) – TheSorm

+2

@TheSorm這將通過JIT編譯器(或只是普通的編譯器)進行優化,不需要這樣做。 – Oleg

+0

@ Oleg哦好吧,我很酷,我從來沒有舒爾什麼編譯器做什麼,所以我嘗試做我自己的事情得到舒爾:D – TheSorm

2

沒有測試它,但以下是根據@ Zefick的答案,應該是更好的性能:

int dirs[] = { -1, -1, -1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 0, 1, 1 }; 

for (int i = 0; i < dirs.length; i += 2) { 
    int xOffset = dirs[i]; 
    int yOffset = dirs[i + 1]; 
    // my code 
}  
2

我跑了江鈴控股基準用這個問題的各種解決方案。我總是在黑洞中消耗2個偏移量的指標。結果如下:

Benchmark         Mode Cnt   Score   Error Units 
Offset2DBenchmark.doubleLoopWithIf  thrpt 3 35425373,827 ± 4242716,439 ops/s 
Offset2DBenchmark.loopOverFlatIndex  thrpt 3 35929636,197 ± 935681,592 ops/s 
Offset2DBenchmark.loopOverIndex   thrpt 3 31438051,279 ± 3286314,668 ops/s 
Offset2DBenchmark.unrolledLoop   thrpt 3 40495297,238 ± 6423961,118 ops/s 
Offset2DBenchmark.unrolledLoopWithLambda thrpt 3 27526581,417 ± 1712524,060 ops/s 


doubleLoopWithIf  = Nested Loops with If to filter 0,0 (TheSorm) 
loopOverFlatIndex  = Single loop with flattend indizes (Oleg) 
loopOverIndex   = Single Loop with 2d indizes (Zefick) 
unrolledLoop   = Completely Unrolled Loop 
unrolledLoopWithLambda = Unrolled Loop consuming a Bifunction<Integer, Integer> 

因此,展開的循環是最快的。稍微慢一點的是帶有if語句和Oleg提出的扁平數組的雙循環。 Zefick的二維數組比您的解決方案更慢。

就像一個演示,這裏是一個測試看起來像什麼:

@Fork(value = 1) 
@Warmup(iterations = 3) 
@Measurement(iterations = 3) 
@Benchmark 
public void unrolledLoopWithLambda(Blackhole bh) { 
    outerOffsets((x, y) -> { 
     bh.consume(x); 
     bh.consume(y); 
    }); 
} 

private void outerOffsets(BiConsumer<Integer, Integer> consumer) { 
    consumer.accept(-1, -1); 
    consumer.accept(-1, 0); 
    consumer.accept(-1, 1); 
    consumer.accept(0, -1); 
    consumer.accept(0, 1); 
    consumer.accept(1, -1); 
    consumer.accept(1, 0); 
    consumer.accept(1, 1); 
} 

所以,除非你想手動展開你的循環,沒有太多可以做,以提高性能。

不幸的是,你沒有告訴使用循環內的代碼是什麼樣的。如果它甚至有點費時,問題如何循環可能會被忽略...

但是你的標題說明你想要這個作爲二維數組的偏移量。我懷疑你可能會在xy以上的更大循環中使用它。您可以通過使用1d數組並獲得更高性能並自行計算索引。

相反的:

array[x][y] 

使用

array[xy] with xy = x + y * xsize 

你應該能夠避免做乘法的。

(這是我第一次跑了標杆與江鈴控股,所以請告訴我,如果我用它完全錯了...)

+0

哇謝謝你所有的工作:)與展開的循環,你的意思只是一個for循環沒有你嗎? – TheSorm

+1

我的意思是展開的循環,你根本不使用循環。你複製和粘貼你的代碼,直到你有8份。然後你硬編碼xOffset和yOffset的值。應該沒問題,因爲你是在表演之後。就可維護性而言,儘可能醜陋。 –

+0

啊是好的謝謝:) – TheSorm