17

Tôi có một mảng hai chiều, nóiLấy các phần tử liền kề trong mảng hai chiều?

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 

Và tôi cần để có được tất cả các số liền kề 1 (2, 3, 4, 5, 6, 7, 8, 9)

Có giải pháp ít xấu xí hơn không:

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

Cảm ơn!

+0

@Nick D: Tại sao loại bỏ các '2d' từ tiêu đề? –

+0

@Ian P: Tôi đoán vì nó là thừa.'Hai chiều' là giống như '2D'. –

Trả lời

17

Nếu bạn không lo lắng về trật tự, sạch nhất có lẽ là sử dụng một vài vòng:

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

Nếu trật tự là rất quan trọng, bạn có thể xây dựng một danh sách tất cả các (dx, dy) theo thứ tự bạn muốn và lặp lại thay vào đó.

Như đã nêu trong các nhận xét, bạn có thể muốn thêm kiểm tra biên. Bạn có thể làm điều đó như thế này (giả sử tự không quan trọng):

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

Bạn cần tính đến các trường hợp cạnh tài khoản. Nếu đặc tả của (x, y) là (0, 0) thì chỉ số mảng của bạn sẽ nằm ngoài giới hạn. Vì điều này có vẻ như mã C# có nghĩa là bạn sẽ nhận được một ngoại lệ. – Eilon

+0

@Eilon: được cập nhật bằng kiểm tra ranh giới. –

1

Trong C++ này có thể trông giống như:

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

Đây không phải là giải pháp rất rõ ràng nhưng rất ngắn.

+0

giải pháp đó không khái quát ở tất cả – twolfe18

+0

@ twolfe18 cảm ơn, cố định – sergtk

11

tôi có thể đi cho một danh sách liên tục của dx, dy cho mỗi hướng, như vậy:

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

Sau đó, bạn muốn lặp qua các hướng dẫn sử dụng một vòng lặp đơn giản:

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

Tất nhiên, bạn có thể sử dụng sizeof(directions)/sizeof(directions[1]) thay vì 8 ở trên.

+0

đây có lẽ là cách thực hiện đẹp nhất –

+0

Xin chào, điều gì sẽ 'x' và' y' ở đây? Cảm ơn. – Unheilig

7

cá nhân, các vòng lặp xấu hơn bản gốc.

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 ] 

Nhưng không chỉ định những gì bạn muốn giá trị - bạn làm theo các hướng khác nhau ngụ ý bạn muốn giá trị trong các biến riêng biệt hay không.

Đối với trò chơi xử lý kiểu sống, bạn thường muốn làm việc trên bitpattern thay vì một mảng giá trị riêng lẻ và bạn có thể quét theo chiều ngang chỉ kiểm tra ba trong số tám ô tại một thời điểm sử dụng bộ đếm và thời gian. Đối với các biến đổi đồ họa, hãy sử dụng thư viện hiện có với hạt nhân 3x3.

Cách khác để xử lý các ranh giới là mở rộng mảng bằng một ô theo từng hướng. Điều này tránh các chi nhánh đắt tiền trong mã chập.

+0

Trong khi tìm kiếm về điều gì khác, tôi tình cờ gặp câu trả lời của bạn. Giải pháp rất đẹp. Tôi tự hỏi ... nó sẽ có thể áp dụng một cái gì đó tương tự nếu mảng giống như một kim tự tháp Pascal? Không phải là "một" kim tự tháp Pascal, chỉ là hình dạng: một mục ở trên cùng, hai ở giữa và ba ở phía dưới? –

0

Đây là giải pháp Ruby. Thuật toán phải hiển nhiên ngay cả đối với những người đọc không quen thuộc với 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 

in

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] 
Các vấn đề liên quan