Создание двумерных массивов и доступ к подмассивам в Ruby - PullRequest
66 голосов
/ 12 ноября 2009

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

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

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

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

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

x[3..8][6]

Как мне избежать или взломать этот лимит?

Ответы [ 9 ]

93 голосов
/ 12 ноября 2009

Есть некоторые проблемы с 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, подобного этому, если бы знал, что объем моих данных становится большим.

31 голосов
/ 12 ноября 2009
rows, cols = x,y  # your values
grid = Array.new(rows) { Array.new(cols) }

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

Как сделать массив ruby ​​

30 голосов
/ 12 ноября 2009

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

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]]
10 голосов
/ 15 июля 2010

Вот случай с трехмерным массивом

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 голосов
/ 12 ноября 2009

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]
2 голосов
/ 17 октября 2013

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

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
0 голосов
/ 27 июля 2014

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

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

=> [[true, true, true], [true, true, true], [true, true, true]]
0 голосов
/ 14 февраля 2013
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's not a[i][j], but a[i[j]]
  end
  puts "\n"
end
0 голосов
/ 23 января 2013

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

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

 #two
row, col = 10, 10
a = [[0]*row]*col
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...