web-dev-qa-db-fra.com

Trouver des voisins dans un tableau à deux dimensions

Existe-t-il un moyen facile de trouver les voisins (c'est-à-dire les huit éléments autour d'un élément) d'un élément dans un tableau à deux dimensions? Il suffit de soustraire et d’ajouter à l’index différentes combinaisons, comme ceci:

array[i-1][i]
array[i-1][i-1]
array[i][i-1]
array[i+1][i]

... Etc.

20
Emil Svansø

(pseudo-code)

row_limit = count(array);
if(row_limit > 0){
  column_limit = count(array[0]);
  for(x = max(0, i-1); x <= min(i+1, row_limit); x++){
    for(y = max(0, j-1); y <= min(j+1, column_limit); y++){
      if(x != i || y != j){
        print array[x][y];
      }
    }
  }
}

Bien sûr, cela prend presque autant de lignes que la solution originale codée en dur, mais avec celle-ci, vous pouvez étendre le "voisinage" autant que vous le pouvez (2 ou 3 cellules plus loin)

27
Seb

Je pense que Ben est correct dans son approche, bien que je puisse le réorganiser, pour éventuellement améliorer la localité.

array[i-1][j-1]
array[i-1][j]
array[i-1][j+1]

array[i][j-1]
array[i][j+1]

array[i+1][j-1]
array[i+1][j]
array[i+1][j+1]

Une astuce pour éviter les problèmes de vérification des limites consiste à rendre les dimensions du tableau 2 plus grandes que nécessaire. Donc, une petite matrice comme celle-ci

3 1 4
1 5 9
2 6 5

est effectivement mis en œuvre comme 

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

puis, en faisant la somme, je peux inscrire de 1 à 3 dans les deux dimensions, et les références de tableau ci-dessus sont garanties comme étant valides, et n’ont aucun effet sur la somme finale. Je suppose que les indices de base c et zéro sont valables. l'exemple

11
EvilTeach

Voici un exemple Javascript fonctionnel issu du pseudo-code d'origine @seb:

function findingNeighbors(myArray, i, j) {
  var rowLimit = myArray.length-1;
  var columnLimit = myArray[0].length-1;

  for(var x = Math.max(0, i-1); x <= Math.min(i+1, rowLimit); x++) {
    for(var y = Math.max(0, j-1); y <= Math.min(j+1, columnLimit); y++) {
      if(x !== i || y !== j) {
        console.log(myArray[x][y]);
      }
    }
  }
}
5
Ryan Alberts

une alternative à @SebaGR, si votre langue le supporte:

var deltas = { {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1},
               {x=-1, y=0},               {x=1, y=0},
               {x=-1, y=1},  {x=0, y=1},  {x=1, y=1} };
foreach (var delta in deltas)
{
    if (x+delta.x < 0 || x + delta.x >= array.GetLength(0) ||
        y+delta.y < 0 || y + delta.y >= array.GetLength(1))
        continue;

    Console.WriteLine("{0}", array[x + delta.x, y + delta.y]);
}

Léger avantage en lisibilité, performances possibles si vous pouvez allouer les deltas de manière statique.

5
FryGuy

array[i][j] a des voisins

array[i-1][j]
array[i][j-1]
array[i-1][j-1]
array[i+1][j]
array[i][j+1]
array[i+1][j+1]
array[i+1][j-1]
array[i-1][j+1]

C’est probablement le moyen le plus simple et le plus rapide d’énumérer tous les voisins possibles. Assurez-vous cependant de vérifier l'index hors limite.

Certaines langues offrent un raccourci, mais je n’en connais aucune.

3
Ben S

Voici une méthode pratique en Python:

def neighbors(array,pos):
    n = []
     string = "array[pos.y+%s][pos.x+%s]"
    for i in range(-1,2):
        for j in range(-1,2):
            n.append(eval(string % (i,j)))
    return n

En supposant que pos soit un objet Point 2D et qu'un tableau est un tableau 2D.

2
AdrianC

Ceci est une implémentation de la réponse de @ Seb en python3 + qui est concise et utilise des générateurs pour des performances maximales:

def neighbours(pos, matrix):
    rows = len(matrix)
    cols = len(matrix[0]) if rows else 0
    for i in range(max(0, pos[0] - 1), min(rows, pos[0] + 2)):
        for j in range(max(0, pos[1] - 1), min(cols, pos[1] + 2)):
            if (i, j) != pos:
                yield matrix[i][j]
1
Salvatore Fiorenza

voici un code pour C #:

public Cell[,] MeetNeigbours(Cell[,] Grid)
    {
        for (int X = 0; X < Grid.GetLength(0); X++)
        {
            for (int Y = 0; Y < Grid.GetLength(1); Y++)
            {
                int NeighbourCount = 0;
                for (int i = -1; i < 2; i++)
                {
                    for (int j = -1; j < 2; j++)
                    {
                        if (CellExists(Grid, (X + i)), (Y + j) && (i != 0 && j != 0))
                        {
                            Grid[X, Y].Neighbours[NeighbourCount] = Grid[(X + i), (Y + j)];
                        }
                        if(!(i == 0 && j == 0))
                        {
                            NeighbourCount++;
                        }
                    }
                }
            }
        }
        return Grid;
    }

    public bool CellExists(Cell[,] Grid, int X, int Y)
    {
        bool returnValue = false;
        if (X >= 0 && Y >= 0)
        {
            if (X < Grid.GetLength(0) && Y < Grid.GetLength(1))
            {
                returnValue = true;
            }
        }

        return returnValue;
    }

avec la classe "Cell" ressemblant à ceci:

public class Cell
{
    public Cell()
    {
        Neighbours = new Cell[8];
    }

    /// <summary>
    /// 0 3 5
    /// 1 X 6
    /// 2 4 7
    /// </summary>
    public Cell[] Neighbours;
}
0
TDM

L’approche que j’adopte habituellement est décrite au bas de ce blog: https://royvanrijn.com/blog/2019/01/longest-path/

Au lieu de coder en dur les directions ou d’avoir deux boucles imbriquées, j’aimerais utiliser une seule boucle entière pour les 8 "directions" et utiliser (i% 3) -1 et (i/3) -1; consultez le blog avec des images.

Il n’est pas aussi profond et s’écrit facilement, il n’ya pas besoin de beaucoup de code!

0
Roy van Rijn

Tout dépend de la nature de vos données. Par exemple, si votre tableau 2D est une matrice logique, vous pouvez convertir des lignes en nombres entiers et utiliser des opérations au niveau des bits pour trouver celles que vous souhaitez. 

Pour une solution plus générale, je pense que vous êtes coincé avec l'indexation, comme la solution SebaGR.

0
Sarah Mei

Les lignes et les colonnes représentent le nombre total de lignes et de colonnes.

Définissez une structure ou une classe CellIndex. Ou vous pouvez simplement renvoyer les valeurs réelles au lieu des index.

public List<CellIndex> GetNeighbors(int rowIndex, int colIndex)
{
var rowIndexes = (new int[] { rowIndex - 1, rowIndex, rowIndex + 1 }).Where(n => n >= 0 && n < Rows);

var colIndexes = (new int[] { colIndex - 1, colIndex, colIndex + 1 }).Where(n => n >= 0 && n < Cols);

return (from row in rowIndexes from col in colIndexes where row != rowIndex || col != colIndex select new CellIndex { Row = row, Col = col }).ToList();
}
0
Krishna

Cela m’a vraiment aidé dans un projet récent, voici donc l’implémentation du pseudo-code de @Seb dans Swift. Ceci suppose que le tableau à deux dimensions est carré:

func adjacentIndexPaths(to indexPath: IndexPath) -> [IndexPath] {
var neighboringSquareIndexes: [IndexPath] = []

// gridSquareCount is the size of the 2D array. For example, in an 8 x 8 [[Array]], gridSquareCount is 8
let maxIndex = gridSquareCount - 1
var neighborRowIndex = max(0, indexPath.section - 1)
var neighborColumnIndex = max(0, indexPath.row - 1)

while neighborRowIndex <= min(indexPath.section + 1, maxIndex) {
    while neighborColumnIndex <= min(indexPath.row + 1, maxIndex) {
        if neighborRowIndex != indexPath.section || neighborColumnIndex != indexPath.row {
            neighboringSquareIndexes.append(IndexPath(row: neighborColumnIndex, section: neighborRowIndex))
        }
        neighborColumnIndex += 1
    }
    neighborRowIndex += 1
    neighborColumnIndex = max(0, indexPath.row - 1)
}

return neighboringSquareIndexes }
0
ArielSD

Etant donné qu’il n’ya que 8 éléments dans une matrice entourant un élément, vous pouvez utiliser un tableau pour stocker différentes valeurs d’index.Par exemple,

  int iarr[8] = {-1,-1,-1,0,0,+1,+1,+1};
  int jarr[8] = {-1,0,+1,-1,+1,-1,0,+1};
  for(int i = 0 ; i < 8 ; i++)
   {
    if(arr[x-iarr[i]][y-jarr[i]] == 1)
    {
     //statements
    }
   }  
  /* x and y are the position of elements from where you want to reach out its neighbour */

comme les deux tableaux ne contiennent que 8 valeurs, l'espace peut ne pas être un problème.

0
Shubh Tripathi
private ArrayList<Element> getNeighbors(Element p) {
    ArrayList<Element> n = new ArrayList<Element>();

    for (int dr = -1; dr <= +1; dr++) {
        for (int dc = -1; dc <= +1; dc++) {
            int r = p.row + dr;
            int c = p.col + dc;

            if ((r >= 0) && (r < ROWS) && (c >= 0) && (c < COLS)) {
                // skip p
                if ((dr != 0) || (dc != 0))
                    n.add(new Element(r, c));
            }               
        }
    }

    return n;
}
0
Vijay M

bien que imbriqué pour les boucles dans les compréhensions de liste soit un peu moche, c’est plus court:

def neighbours(m, i, j):
    return [m[x][y] for x in [i-1,i,i+1] for y in [j-1,j,j+1] if x in range(0,len(m)) and y in range(0,len(m[x])) and (x,y) != (i,j)]
0
hansaplast