web-dev-qa-db-fra.com

Obtenir des éléments adjacents dans un tableau à deux dimensions?

J'ai un tableau en deux dimensions, disons

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

Et j'ai besoin d'obtenir tous les nombres adjacents à 1 (2, 3, 4, 5, 6, 7, 8, 9)

Y a-t-il une solution moins laide que:

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

Merci!

21
Ian P

Si vous n'êtes pas inquiet à propos de la commande, le plus propre consiste probablement à utiliser quelques boucles:

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

Si l'ordre est important, vous pouvez créer une liste de tous les éléments (dx, dy) dans l'ordre de votre choix et effectuer une itération à la place.

Comme indiqué dans les commentaires, vous souhaiterez probablement ajouter des contrôles de limites. Vous pouvez le faire comme ceci (en supposant que l'ordre n'a pas d'importance):

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

J'irais probablement pour une liste constante de dx, dy pour chaque direction, comme suit:

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

Ensuite, vous parcourez les instructions à l'aide d'une simple boucle:

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

Vous pouvez bien sûr utiliser sizeof(directions) / sizeof(directions[1]) au lieu du 8 ci-dessus.

12
gooli

personnellement, les boucles sont plus laides que l'original.

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 ]

Mais sans spécifier pour quoi vous voulez que les valeurs - ce que vous faites dans les différentes directions implique que vous vouliez ou non les valeurs dans des variables séparées.

Pour le traitement de style de jeu, vous voulez généralement travailler sur un bitpattern plutôt que sur un tableau de valeurs individuelles, et vous pouvez analyser horizontalement seulement trois des huit cellules à la fois à l'aide d'accumulateurs et de temporaires. Pour les convolutions graphiques, utilisez une bibliothèque existante avec un noyau 3x3.

L'autre façon de traiter les limites consiste à agrandir le tableau d'une cellule dans chaque direction. Cela évite des branches coûteuses dans le code de convolution.

7
Pete Kirkham

Dans C++ cela peut ressembler à:

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

Ce n'est pas une solution très claire mais très courte.

2
sergtk

Voici une solution Ruby. L'algorithme devrait être évident même pour les lecteurs qui ne sont pas familiers avec Ruby. Notez comment j'ai calculé les lignes et les colonnes à itérer (qui seraient écrites de la même manière dans la plupart des langues). Cela me semble beaucoup plus net que, par exemple, "de max(r-1, 0) à min(r+1, arr.size-1)" pour les index des lignes à itérer.

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

empreintes

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]
0
Cary Swoveland