2017-09-14 73 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