Подтвердить что ты не робот

Получать смежные элементы в двумерном массиве?

У меня есть двумерный массив, скажем

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

Спасибо!

4b9b3361

Ответ 1

Если вас не беспокоит порядок, самым чистым, вероятно, будет использование пары петель:

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

Ответ 2

Я бы, вероятно, пошел для постоянного списка dx, dy для каждого направления, например:

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

Затем вы будете перебирать маршруты, используя простой цикл:

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

Вы можете, конечно, использовать sizeof(directions) / sizeof(directions[1]) вместо 8 выше.

Ответ 3

лично, петли более уродливые, чем оригиналы.

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 ]

Но без указания того, что вы хотите, значения для - то, что вы делаете в разных направлениях, подразумевает, хотите ли вы значения в отдельных переменных или нет.

Для игры в стиле жизни вы обычно хотите работать на битпаттере в любом случае, а не в массиве отдельных значений, и вы можете сканировать горизонтально, проверяя только три из восьми ячеек за раз, используя аккумуляторы и временные файлы. Для графических сверток используйте существующую библиотеку с ядром 3x3.

Другим способом борьбы с границами является расширение массива на одну ячейку в каждом направлении. Это позволяет избежать дорогостоящих ветвей в коде свертки.

Ответ 4

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

Это не очень четкое решение, но очень короткое.

Ответ 5

Здесь решение Ruby. Алгоритм должен быть очевиден даже для читателей, которые не знакомы с Ruby. Обратите внимание, как я вычислил строки и столбцы, по которым нужно выполнить итерацию (что было бы написано аналогично на большинстве языков). Мне кажется, это намного чище, чем, например, "от max(r-1, 0) до min(r+1, arr.size-1) " для индексов строк, которые нужно перебирать.

def adjacent(arr, r, c)
  rows_ndx = arr.each_index.select { |i| (i-r).abs < 2 }
  cols_ndx = arr.first.size.times.select { |j| (j-c).abs < 2 }
  rows_ndx.each_with_object([]) do |i,a| 
    cols_ndx.each { |j| a << arr[i][j] unless [i,j] == [r,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|
  (0..3).each do |j|
    puts "adjacent to #{arr[i][j]} at r=#{i}, c=#{j} = #{adjacent(arr, i, j)}"
  end
end

печать

adjacent to -1 at r=0, c=0 = [2, -2, 9]
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 -2 at r=1, c=0 = [-1, 2, 9, -3, 8]
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 -3 at r=2, c=0 = [-2, 9, 8, -4, -5]
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]

Ответ 6

генератор питона, чтобы получить соседние узлы в данном matirx

def gen_adjacent_node(matrix_2d, node=(0,0)):
    rows = len(matrix_2d)
    columns = len(matrix_2d[0])
    for r in [-1, 0, 1]:
        for c in [-1, 0, 1]:
            if r == c == 0:
                continue
            # check valid index
            if 0 <= node[0]+r < rows and 0 <= node[1]+c < columns:
                # print((node[0]+i, node[1]+j))
                yield (node[0]+r, node[1]+c)