17

我有一个二维阵列,说获取二维数组中的相邻元素?

0 0 0 0 0 
0 2 3 4 0 
0 9 1 5 0 
0 8 7 6 0 
0 0 0 0 0 

,我需要得到所有相邻的数字为1(2,3,4,5,6,7,8,9)

有没有比这更难看的解决方案:

topLeft = array[x-1][y-1] 
top = array[x][y-1] 
topRight = array[x+1][y-1] 
# etc 

谢谢!

+0

@Nick d:为什么从标题中删除 '2D'? – 2010-01-10 02:14:18

+0

@Ian P:我猜是因为它是多余的。“二维”与“2D”相同。 – 2010-01-10 02:48:06

回答

17

如果你不担心顺序,最干净的可能是使用一对夫妇的循环:

result = new List<int>(8); 
for (dx = -1; dx <= 1; ++dx) { 
    for (dy = -1; dy <= 1; ++dy) { 
     if (dx != 0 || dy != 0) { 
      result.Add(array[x + dx][y + dy]); 
     } 
    } 
} 

如果顺序很重要,你可以构造所有(DX,DY名单)按照你想要的顺序,然后遍历它。

正如评论中指出的那样,您可能想要添加边界检查。你可以做这样的(假设顺序无所谓):

List<int> result = new List<int>(8); 
for (int dx = (x > 0 ? -1 : 0); dx <= (x < max_x ? 1 : 0); ++dx) 
{ 
    for (int dy = (y > 0 ? -1 : 0); dy <= (y < max_y ? 1 : 0); ++dy) 
    { 
     if (dx != 0 || dy != 0) 
     { 
      result.Add(array[x + dx][y + dy]); 
     } 
    } 
} 
+0

您需要考虑边缘情况。如果(x,y)的规范是(0,0),那么你的数组索引将超出范围。由于这看起来像C#代码,这意味着你会得到一个异常。 – Eilon 2010-01-10 01:37:06

+0

@Eilon:更新了边界检查。 – 2010-01-10 01:55:42

1

C++这可能看起来像:

vector<int> adj; 
for (int i = 0; i < 9; i++) 
    if (i != 4) adj.push_back(array[x + i/3 - 1][y + i%3 - 1]); 

这不是很清楚的解决方案,但很短。

+0

该解决方案根本没有推广 – twolfe18 2010-01-10 02:31:41

+0

@ twolfe18谢谢,修正 – sergtk 2010-01-10 12:48:05

11

我可能会去DX恒定列表,DY每个方向,就像这样:

for (int i = 0; i < 8; i++) { 
    // use x + directions[i].dx; 
    // use y + directions[i].dy; 
} 

struct { 
    int dx; 
    int dy; 
} directions[] = {{-1,-1,},{-1,0,},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}}; 

然后你会使用一个简单的循环在迭代方向

您当然可以使用sizeof(directions)/sizeof(directions[1])而不是上面的8

+0

这可能是最好看的实现 – 2014-12-06 02:14:51

+0

嗨,'x'和'y'会在这里?谢谢。 – Unheilig 2015-06-12 04:27:37

7

个人而言,环路比原始环境更丑陋。

topLeft = array[ x - 1 ][ y - 1 ] 
top  = array[ x  ][ y - 1 ] 
topRight = array[ x + 1 ][ y - 1 ] 

midLeft = array[ x - 1 ][ y  ] 
midRight = array[ x + 1 ][ y  ] 

botLeft = array[ x - 1 ][ y + 1 ] 
bot  = array[ x  ][ y + 1 ] 
botRight = array[ x + 1 ][ y + 1 ] 

但是,如果没有指定你想要的价值观 - 你在不同的方向做意味着你是否希望在不同的变量或没有价值。

对于生活方式处理游戏,您通常希望无论如何都要使用bitpattern,而不是单个数值的阵列,并且您可以使用累加器和临时对象一次只对三个单元格进行水平扫描。对于图形卷积,使用带有3x3内核的现有库。

处理边界的另一种方法是在每个方向上将数组扩展一个单元格。这避免了卷积码中昂贵的分支。

+0

在寻找别的东西时,我偶然发现了答案。很好的解决方案。我想知道......如果阵列像帕斯卡金字塔一样,是否可以应用类似的东西?不是“一个”帕斯卡金字塔,只是形状:一个入口在顶部,两个在中间,三个在底部? – 2016-05-16 11:16:46

0

这是一个Ruby解决方案。即使对不熟悉Ruby的读者,该算法也应该是明显的。

def adjacent(arr, r, c) 
    last_row, last_col = arr.size-1, arr.first.size-1 
    ([r-1,0].max..[r+1,last_row].min).each_with_object([]) do |i, a| 
    ([c-1,0].max..[c+1,last_col].min).each { |j| a << arr[i][j] unless i==r && j==c } 
    end 
end 

arr = [ 
    [-1, 2, 3, 4], 
    [-2, 9, 1, 5], 
    [-3, 8, 7, 6], 
    [-4, -5, -6, -7] 
] 

(0..2).each do |i| 
    (1..3).each do |j| 
    puts "adjacent to #{arr[i][j]} at r=#{i}, c=#{j} = #{adjacent(arr, i, j)}" 
    end 
end 

打印

adjacent to 2 at r=0, c=1 = [-1, 3, -2, 9, 1] 
adjacent to 3 at r=0, c=2 = [2, 4, 9, 1, 5] 
adjacent to 4 at r=0, c=3 = [3, 1, 5] 
adjacent to 9 at r=1, c=1 = [-1, 2, 3, -2, 1, -3, 8, 7] 
adjacent to 1 at r=1, c=2 = [2, 3, 4, 9, 5, 8, 7, 6] 
adjacent to 5 at r=1, c=3 = [3, 4, 1, 7, 6] 
adjacent to 8 at r=2, c=1 = [-2, 9, 1, -3, 7, -4, -5, -6] 
adjacent to 7 at r=2, c=2 = [9, 1, 5, 8, 6, -5, -6, -7] 
adjacent to 6 at r=2, c=3 = [1, 5, 7, -6, -7]