Хобрук: Ваш путь к мастерству в программировании

Найти элементы, окружающие элемент в массиве

У меня есть многомерный массив, я хочу получить элементы, окружающие определенный элемент в этом массиве.

Например, если у меня есть следующее:

[[1,2,3,4,5,6]
 [8,9,7,5,2,6]
 [1,6,8,7,5,8]
 [2,7,9,5,4,3]
 [9,6,7,5,2,1]
 [4,7,5,2,1,3]]

Как мне найти все 8 элементов вокруг любого из вышеперечисленных элементов? И как мне позаботиться об элементах по краям?

Я понял, что один из способов — написать для этого 9-строчный код, что очевидно, но есть ли лучшее решение?


  • Используйте по модулю (%), чтобы позаботиться о случаях на краях... 05.10.2012

Ответы:


1

Вы можете использовать «массив направлений» в форме

[[-1,-1], [-1,0],[1,0]..and so on]

И метод, который берет координату точки и перебирает массив направлений -> добавляет номера направлений к координатам, проверяет, не выходят ли индексы за пределы, и собирает результаты. Что-то вроде этого:

private static int[][] directions = new int[][]{{-1,-1}, {-1,0}, {-1,1},  {0,1}, {1,1},  {1,0},  {1,-1},  {0, -1}};

static List<Integer> getSurroundings(int[][] matrix, int x, int y){
    List<Integer> res = new ArrayList<Integer>();
    for (int[] direction : directions) {
        int cx = x + direction[0];
        int cy = y + direction[1];
        if(cy >=0 && cy < matrix.length)
            if(cx >= 0 && cx < matrix[cy].length)
                res.add(matrix[cy][cx]);
    }
    return res;
}
05.10.2012
  • Привет, хорошее решение. Можно ли расширить это, например, для получения окружающих элементов вокруг внутреннего набора окружающих элементов одного индекса? Спасибо. 12.06.2015

  • 2

    Для (i, j) ->

                  (i - 1, j - 1)
                  (i - 1, j)
                  (i - 1, j + 1)
    
                  (i, j - 1)
                  (i, j + 1)
    
                  (i + 1, j - 1)
                  (i + 1, j)
                  (i + 1, j + 1)
    

    Теперь по краям вы можете проверить num % row == 0, затем на краю строки... и, num % col == 0, затем на краю столбца..

    Вот как вы можете действовать: -

    Учитывая индекс (i, j).. Вы можете найти элементы в строках, смежных с j для i - 1, затем i, а затем i + 1. (ПРИМЕЧАНИЕ: - для индекса i вам просто нужно получить доступ к j - 1 и j + 1)

    Впоследствии вы также можете проверить наличие row edge и column edge..

    Здесь вы можете посмотреть на код ниже, как это может произойти: -

        // Array size
        int row = 6;
        int col = 6;
        // Indices of concern
        int i = 4;
        int j = 5;
    
        // To the left of current Column
        int index = i - 1;
        for (int k = -1; k < 2; k++) {
            if (index % row > 0 && ((j + k)  % col) > 0) {
                System.out.println(arr[index][j + k]);
            }
        }
    
    
        // In the current Column
        index = i;
    
        // Increment is 2 as we don't want (i, j)
        for (int k = -1; k < 2; k = k + 2) {            
            if (index % row > 0 && ((j + k)  % col) > 0) {
                System.out.println(arr[index][j + k]);
            }
        }
    
        // To the right of current Column
        index = i + 1;
        for (int k = -1; k < 2; k++) {
            if (index % row > 0 && ((j + k)  % col) > 0) {
                System.out.println(arr[index][j + k]);
            }
    
        }
    

    ОБНОВЛЕНИЕ: - Вышеприведенный код можно еще больше упростить.. Но я оставляю эту задачу вам.. СОВЕТ: - Отсюда вы можете сократить один цикл for..

    05.10.2012
  • Кажется, есть некоторые 1, которые должны быть либо i, либо j (случай 2 и случай 7). 05.10.2012
  • @Rohit Jain: спасибо, я понял это, но дело в том, что я должен сделать это для всех элементов многомерного массива, поэтому мне нужно найти обобщенный способ обхода всех соседних элементов 05.10.2012
  • @vineetrok Если вы измените каждый (i, j) на (i % rows, j % cols), это будет работать как общий случай. 05.10.2012
  • @Baz.. Нет, это то, что я написал.. Сначала я написал 1 во втором регистре, но потом заменил его на i. 05.10.2012
  • @vineetrok.. Перед доступом к индексу вам нужно проверить, имеют ли ваши (x-index % rows ›= 0) и (y-index % col ›= 0) доступ к нему только у вас. 05.10.2012
  • @RohitJain Я не понимаю твоего комментария ко мне. Комментарий к vineetrok некорректен. Вам не нужно проверять это заранее. Вы можете использовать модуль в доступе. Смотрите мой предыдущий комментарий. 05.10.2012
  • @Baz.. На самом деле ранее я написал свой 2-й элемент: - (i - 1, j) как (1 - 1, j).. Итак, я подумал, что вы говорили об этом в своем первом комментарии.. А что касается граничного условия, да, нам не нужно проверять заранее, мы можем просто доступ по модулю.. Я дал идею OP.. Спасибо :) 05.10.2012
  • @vineetrok .. Вы можете проверить код .. это поможет вам лучше понять .. И посмотрите мое ОБНОВЛЕНИЕ и ПОДСКАЗКУ под кодом .. 05.10.2012
  • @Baz.. На самом деле вам нужно предварительно проверить граничное значение. В противном случае индекс переместится в начало.. Если мы получим к ним доступ без проверки.. Посмотрите мой обновленный код.. И прокомментируйте его.. 05.10.2012
  • @RohitJain Нет, вам не нужно проверять это заранее. Допустим, вы хотите получить доступ к индексу -1 и у вас есть 8 строк. Тогда arr[-1 % 8] равно arr[7], что является допустимым и правильным индексом. 05.10.2012
  • @Baz.. Да, это действительно так, но arr[7] не считается среди окружающих arr[0].. Итак, чтобы исключить их использование, нам нужно проверить .. 05.10.2012
  • @Baz.. Я думал, что он хотел избежать выхода из edge.. Потому что, если мы продолжим цикл до другого конца, когда будет достигнуто ребро.. Это не будет точно рядом с элементом edge.. Я думаю, что только OP может скажите, что он хочет.. (Мой текущий код остановится на EDGE, и если мы не проверим условие, он переместится на другой конец.) 05.10.2012
  • @RohitJain Спасибо за ответ, я уже нашел способ сделать это. я отправил это как ответ :) 05.10.2012

  • 3
    for (i = 0; i < array.length; i++) {
                for (j = 0; j < array[i].length; j++) {
                    for (x = Math.max(0, i - 1); x <= Math.min(i + 1, array.length); x++) {
                        for (y = Math.max(0, j - 1); y <= Math.min(j + 1,
                                array[i].length); y++) {
                            if (x >= 0 && y >= 0 && x < array.length
                                    && y < array[i].length) {
                                if(x!=i || y!=j){
                                System.out.print(array[x][y] + " ");
                                }
                            }
                        }
                    }
                    System.out.println("\n");
                }
            }
    

    Спасибо всем, кто ответил, но я понял это с помощью этот пост, который я нашел только что, и выше есть решение. еще раз спасибо :)

    05.10.2012
  • @vineetrok.. Хорошо, что вы нашли решение.. Но почему вы не выполнили поиск, прежде чем публиковать вопрос здесь?? 05.10.2012
  • да, я сделал, но я использовал это слово, окружающие элементы, в тот момент, когда я использовал соседние, я получил ответ в другом вопросе: p 05.10.2012
  • да, запутался в этом! мой ответ, я думаю, дает лучшее решение (хотя он взят из другого вопроса) 05.10.2012
  • @vineetrok.. В этом нет проблем.. Вы всегда должны принимать ответ, который лучше всего соответствует вашим потребностям, а также является лучшим, по вашему мнению.. Это будет полезно, когда другие пользователи увидят его.. Принятый ответ всегда находится по адресу топ.. Значит, он должен быть лучшим.. 05.10.2012

  • 4

    Базовый случай - просто получить соседние элементы путем индексации сдвига. Для (i,j) это будет (i + 1, j), (i - 1, j) и т. д.

    На краях я использую два подхода:

    1. Оператор по модулю % позволяет избежать исключения IndexOutOfBounds, но иногда его путают с неправильной индексацией элементов.
    2. Оберните матрицу одним слоем элементов по умолчанию. Он добавляет дополнительное пространство для хранения матриц, но делает ваш код более читабельным без перехвата исключений, множества if и так далее. Этот трюк часто используют при представлении лабиринта в виде матрицы.

    Пример: ваш элемент по умолчанию равен 0.

    0 0 0 0 0 0
    0 1 2 3 4 0
    0 2 6 7 3 0
    0 1 3 5 7 0
    0 2 4 6 2 0
    0 0 0 0 0 0
    

    Примечание: не забывайте перебирать фактический размер массива, а не расширенный.

    05.10.2012

    5

    Это мое решение вашей проблемы, написанное на Ruby. Вместо того, чтобы вычислять, находится ли элемент на краю, вы можете получить доступ к элементам "над" краем и обработать значения "nil" или исключения, которые там происходят. Затем удалите значения "nil" из окончательного списка. Это решение не так хорошо, как вычисление того, находится ли какая-то «точка» за краем или нет.

    big_map = [[1,2,3,4,5,6],
               [8,9,7,5,2,6],
               [1,6,8,7,5,8],
               [2,7,9,5,4,3],
               [9,6,7,5,2,1],
               [4,7,5,2,1,3]]
    
    # monkey patch classes to return nil.
    [NilClass, Array].each do |klass|
        klass.class_eval do
            def [](index)
                return nil if index < 0 or index > self.size rescue nil
                self.fetch(index) rescue nil
            end
        end
    end
    
    class Array
    
        # calculate near values and remove nils with #compact method.   
        def near(i,j)
            [ self[i - 1][j - 1], self[i - 1][j - 0], self[i - 1][j + 1],
              self[i - 0][j - 1],                     self[i - 0][j + 1],
              self[i + 1][j - 1], self[i + 1][j - 0], self[i + 1][j + 1],
            ].compact
        end
    end
    
    puts big_map.near(1,1).inspect
    # => [1, 2, 3, 8, 7, 1, 6, 8]
    
    puts big_map.near(0,0).inspect
    # => [2, 8, 9]
    
    puts big_map.near(5,5).inspect
    # => [2, 1, 1]
    
    05.10.2012

    6

    Я работал над той же проблемой и придумал небольшое оптимизированное решение для поиска окружающих чисел любой точки в 2D-матрице, надеюсь, это поможет, пожалуйста, прокомментируйте, могу ли я каким-то образом сократить логику Код: -

    import java.util.ArrayList;
    
    public class test {
        public static void main(String[] arg){
    
            int[][] arr = {{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};
            //int[][] arr = {{width,2,3},{4,5,6},{7,8,9}};
            ArrayList<Integer> al = new ArrayList<Integer>();
            int x = 2, y = 2;
            int width = 2; //change the value of width, according to the requirement 
            for(int i = 0; i < 5; i++){
                for(int j = 0; j < 5; j++){
                    if( (i == (x-width) && ( (y+width) >= j && j >= (y-width))) || (i == (x+width) && ( (y+width) >= j && j >= (y-width))) || (j == (y-width) && ( (x+width) >= i && i >= (x-width))) || (j == (y+width) && ( (x+width) >= i && i >= (x-width)))  ){
                        //if( x >= 0 && i < (i+width) && y >= 0 && j < (j+width))
                            {
                            al.add(arr[i][j]);
                            }
                    }
                }
            }
            System.out.println(al);
        }
    
    }
    
    13.06.2016

    7

    Вы не упомянули, хотите ли вы циклических соседей для ребер или игнорируете циклических соседей. Предполагая, что вам нужны циклические соседи, вот код,

    List<Integer> getNeighbours(int[][] mat, int x, int y){
      List<Integer> ret = new ArrayList<Integer>();
      int rows = mat.length;
      int cols = mat[0].length;
      for(int i=-1,i<=1;i++)
        for(int j=-1;j<=1;j++)
          if(i||j) ret = ret.add(mat[(x+i)%rows][(y+j)%cols]);
      return ret;
    }
    
    06.09.2017

    8
    (x-1, y-1) -> upper left
    (x-1, y) -> left
    (x-1, y+1) -> lower left
    

    (x, y+1) -> up
    (x, y) -> current position
    (x, y-1) -> down
    

    (x+1, y+1) -> upper right
    (x+1, y) -> right
    (x+1, y-1) -> lower right
    

    Вы можете использовать это как руководство. Теперь все, что вам нужно сделать, это добавить их в try catch.

     for( int x=0; x<arr.length; x++ ){
      for(int y=0; y<arr[x].length; y++){
      if( arr[x][y] == 8 ){
        try{
          System.out.println("Upper Left is: " + arr[x-1][y-1]);
        }catch(ArrayIndexOutOfBoundsException e){
         //do something
        }
    
    
        try{
          System.out.println("Left is: " + arr[x-1][y]);
        }catch(ArrayIndexOutOfBoundsException e){
         //do something
        }
    
        //.....and others
       }
      }
    
    05.10.2012
  • Вы должны выполнить проверку границ, используя оператор modulo (%). Вам не нужны блоки try-catch для этого.. 05.10.2012
  • @gekkostate Если вы измените исключение, почему бы не изменить и другое? 05.10.2012
  • @Baz Извините, я не видел этого исключения. 06.10.2012
  • Новые материалы

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

    Введение в Джанго Фреймворк
    Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..

    Настольный ПК как «одно кольцо, чтобы править всеми» домашних компьютеров
    Вид после 9 месяцев использования С настольных компьютеров все началось, но в какой-то момент они стали «серверами», и мы все перешли на ноутбуки. В прошлом году я столкнулся с идеей настольных..

    Расширенные методы безопасности для VueJS: реализация аутентификации без пароля
    Руководство, которое поможет вам создавать безопасные приложения в долгосрочной перспективе Безопасность приложений часто упускается из виду в процессе разработки, потому что основная..

    стройный-i18следующий
    Представляем стройную оболочку для i18next. Эта библиотека, основанная на i18next, заключает экземпляр i18next в хранилище svelte и отслеживает события i18next, такие как languageChanged,..