Создайте двумерные массивы и подматрицы доступа в Ruby

Интересно, есть ли возможность создать двухмерный массив и быстро получить доступ к любому горизонтальному или вертикальному подварианту?

Я считаю, что мы можем получить доступ к горизонтальному вспомогательному массиву в следующем случае:

x = Array.new(10) { Array.new(20) }

x[6][3..8] = 'something'

Но насколько я понимаю, мы не можем получить к нему доступ так:

x[3..8][6]

Как я могу избежать или взломать этот предел?

Ответ 1

Есть некоторые проблемы с 2-мерным Arrays способом их реализации.

a= [[1,2],[3,4]]
a[0][2]= 5 # works
a[2][0]= 6 # error

Hash как Array

Я предпочитаю использовать Hashes для многомерного Arrays

a= Hash.new
a[[1,2]]= 23
a[[5,6]]= 42

Это имеет то преимущество, что вам не нужно вручную создавать столбцы или строки. Вставка в хэши почти O (1), поэтому здесь нет недостатка, если ваш Hash не становится слишком большим.

Вы даже можете установить значение по умолчанию для всех не указанных элементов

a= Hash.new(0)

Итак, теперь о том, как получить подмассивы

(3..5).to_a.product([2]).collect { |index| a[index] }
[2].product((3..5).to_a).collect { |index| a[index] }

(a..b).to_a работает в O (n). Получение элемента из Hash составляет почти O (1), поэтому сбор выполняется в почти O (n). Невозможно сделать это быстрее, чем O (n), так как копирование n элементов всегда равно O (n).

Hashes могут иметь проблемы, когда они становятся слишком большими. Поэтому я бы дважды подумал о реализации многомерного Array, как это, если бы я знал, что мой объем данных становится большим.

Ответ 2

rows, cols = x,y  # your values
grid = Array.new(rows) { Array.new(cols) }

Что касается доступа к элементам, эта статья довольно хороша для поэтапного способа инкапсуляции массива так, как вы хотите:

Как рубиновый массив

Ответ 3

Вы не указали свою фактическую цель, но, возможно, это может помочь:

require 'matrix'  # bundled with Ruby
m = Matrix[
 [1, 2, 3],
 [4, 5, 6]
]

m.column(0) # ==> Vector[1, 4]

(и векторы действуют как массивы)

или, используя аналогичную нотацию, которую вы желаете:

m.minor(0..1, 2..2) # => Matrix[[3], [6]]

Ответ 4

Здесь случай трехмерного массива

class Array3D
   def initialize(d1,d2,d3)
    @data = Array.new(d1) { Array.new(d2) { Array.new(d3) } }
   end

  def [](x, y, z)
    @data[x][y][z]
  end

  def []=(x, y, z, value)
    @data[x][y][z] = value
  end
end

Вы можете получить доступ к подразделам каждого массива точно так же, как и любой другой массив Ruby. @data [0..2] [3..5] [8..10] = 0 и т.д.

Ответ 5

x.transpose[6][3..8] или x[3..8].map {|r| r [6]} даст то, что вы хотите.

Пример:

a = [ [1,  2,  3,  4,  5],
      [6,  7,  8,  9,  10],
      [11, 12, 13, 14, 15],
      [21, 22, 23, 24, 25]
    ]

#a[1..2][2]  -> [8,13]
puts a.transpose[2][1..2].inspect   # [8,13]
puts a[1..2].map {|r| r[2]}.inspect  # [8,13]

Ответ 6

Я уверен, что это может быть очень просто

2.0.0p247 :032 > list = Array.new(5)

 => [nil, nil, nil, nil, nil] 

2.0.0p247 :033 > list.map!{ |x| x = [0] }

 => [[0], [0], [0], [0], [0]] 

2.0.0p247 :034 > list[0][0]

  => 0

Ответ 7

a = Array.new(Array.new(4))

0.upto(a.length-1) do |i|
  0.upto(a.length-1) do |j|
    a[i[j]] = 1
  end
end

0.upto(a.length-1) do |i|
  0.upto(a.length-1) do |j|
    print a[i[j]] = 1 #It not a[i][j], but a[i[j]]
  end
  puts "\n"
end

Ответ 8

Вот простая версия

 #one
 a = [[0]*10]*10

 #two
row, col = 10, 10
a = [[0]*row]*col

Ответ 9

Вот простой способ создания массива "2D".

2.1.1 :004 > m=Array.new(3,Array.new(3,true))

=> [[true, true, true], [true, true, true], [true, true, true]]