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]