Оптимизированный цикл для массива с использованием ruby - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть (m = row-1, n = cols-1) размерная матрица.

И я передал i методу, который будет возвращать массив следующим образом (предоставляется i <= m,n)

Предположим, что n = 0, поэтому для матрицы 4x4 это будетвернуть положение граничных элементов.

Не рассматривайте ниже как синтаксис ruby, получите только поток.

square = [[i,i] -> [i, m-i] -> [n-i, m-1] -> [n-i, i] -> [i,i]]

(данные не повторяются выше)

Я достиг вышев режиме рекурсии путем установки параметров, но мне нужен более легкий / оптимизированный трюк.

Обновление - для пользователя sawa

arr = [*1..16].each_slice(4).to_a
m,n = arr.length-1, arr[0].length-1

loop_count = 0

output = [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [4, 1], [4, 2], [3, 2], [2, 2], [1, 2], [0, 2], [0, 1]]

loop_count = 1

output = [[1, 1], [2, 1], [2, 2], [1, 2]]

Ответы [ 3 ]

0 голосов
/ 29 ноября 2018

Здесь мы можем использовать Matrix методы для преимущества, в частности Matrix :: build , Matrix # minor и Matrix # [] .

Код

require 'matrix'

def border_indices(nrows, ncols, i)
  m = Matrix.build(nrows, ncols) { |r,c| [r,c] }.minor(i..nrows-1-i, i..ncols-1-i)
  [[1,0,m.row_count-1], [0,1,m.column_count-1],
   [-1,0,m.row_count-1], [0,-1,m.column_count-2]].
    each_with_object([[0,0]]) do |(x,y,n),a|
      n.times { a << [a.last.first+x, a.last.last+y] }
    end.map { |i,j| m[i,j] }
end

Примеры

nrows = 5
ncols = 6

border_indices(nrows, ncols, 0)
  #=> [[0, 0], [1, 0], [2, 0], [3, 0],
  #    [4, 0], [4, 1], [4, 2], [4, 3], [4, 4],
  #    [4, 5], [3, 5], [2, 5], [1, 5],
  #    [0, 5], [0, 4], [0, 3], [0, 2], [0, 1]]
border_indices(nrows, ncols, 1)
  #=> [[1, 1], [2, 1],
  #    [3, 1], [3, 2], [3, 3],
  #    [3, 4], [2, 4],
  #    [1, 4], [1, 3], [1, 2]]
border_indices(nrows, ncols, 2)
  #=> [[2, 2], [2, 3]]

Объяснение

Рассмотрим вычисление border_indices(5, 6, 1).

nrows = 5
ncols = 6
i = 1
mat = Matrix.build(nrows, ncols) { |r,c| [r,c] }
  #=> Matrix[[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5]],
  #          [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]],
  #          [[2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5]],
  #          [[3, 0], [3, 1], [3, 2], [3, 3], [3, 4], [3, 5]],
  #          [[4, 0], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5]]]
m = mat.minor(i..nrows-1-i, i..ncols-1-i)
  #=> mat.minor(1..3, 1..4)
  #=> Matrix[[[1, 1], [1, 2], [1, 3], [1, 4]],
  #          [[2, 1], [2, 2], [2, 3], [2, 4]],
  #          [[3, 1], [3, 2], [3, 3], [3, 4]]]
b = [[1,0,m.row_count-1], [0,1,m.column_count-1],
     [-1,0,m.row_count-1], [0,-1,m.column_count-2]]
  #=> [[1, 0, 2], [0, 1, 3], [-1, 0, 2], [0, -1, 2]]
c = b.each_with_object([[0,0]]) do |(x,y,n),a|
      n.times { a << [a.last.first+x, a.last.last+y] }
    end
  #=> [[0, 0], [1, 0],
  #    [2, 0], [2, 1], [2, 2],
  #    [2, 3], [1, 3],
  #    [0, 3], [0, 2], [0, 1]]
c.map { |i,j| m[i,j] }
  #=> [[1, 1], [2, 1],
  #    [3, 1], [3, 2], [3, 3],
  #    [3, 4], [2, 4],
  #    [1, 4], [1, 3], [1, 2]]

Обратите внимание, что при вычислении c, a.last - это последняя пара индексов, добавленных в создаваемый массив (a.last = [a.last.first, a.last.last]).

0 голосов
/ 29 ноября 2018

Следующее будет работать для обоих случаев m == n и m != n.

Надеюсь, все рассмотрят, что означает матричная переменная ниже (массив 2 D)

def matrixRotation(matrix)
    m,n = matrix.length-1, matrix[0].length-1
    loop_count = [m,n].min/2
    0.upto(loop_count) do |i|
        indices = []
        i.upto(m-i) { |j| indices << [j, i] }
        i.upto(n-i) { |j| indices << [m-i, j] }
        i.upto(m-i) { |j| indices << [m-j, n-i] }
        i.upto(n-i) { |j| indices << [i, n-j] }
        puts "-------------- For Layer #{i+1} ---------------", nil
        indices = indices.uniq
        values = indices.map { |x| matrix[x[0]][x[1]] }
        puts 'indices:', indices.inspect, nil, 'values:', values.inspect
    end
end
0 голосов
/ 28 ноября 2018

Я закончил с этим решением, но я думаю, что есть лучший выход.

Сначала определите метод для печати матрицы, отображаемой по индексам, просто чтобы проверить, верен ли идентификатор результата:

def print_matrix(n,m)
  range_n, range_m = (0..n-1), (0..m-1)
  mapp = range_m.map { |y| range_n.map { |x| [x, y] } }
  mapp.each { |e| p e }
  puts "-" * 8 * n
end

Затем определите метод, который возвращает кадр, начиная с цикла s (где 0 - внешний кадр):

def frame (n, m, s = 0)
  res = []
  return res if (s >= n/2 and s >= m/2) and (n.even? or m.even?)
  (s..n-s-1).each { |x| res << [x,s] }
  (s..m-s-1).each { |y| res << [res.last[0], y] }
  (res.last[0].downto s).each { |x| res << [x, res.last[1]] }
  (res.last[1].downto s).each { |y| res << [res.last[0], y] }
  res.uniq
end

Теперь вызовите методы и проверьте вывод:

n, m, loops = 4, 4, 1
print_matrix(n,m)
frame(n, m, loops)

# [[0, 0], [1, 0], [2, 0], [3, 0]]
# [[0, 1], [1, 1], [2, 1], [3, 1]]
# [[0, 2], [1, 2], [2, 2], [3, 2]]
# [[0, 3], [1, 3], [2, 3], [3, 3]]
# --------------------------------
# [[1, 1], [2, 1], [2, 2], [1, 2]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...