Возможно, это просто моя нехватка способностей найти здесь эту проблему, но я не могу найти ничего о том, как создавать многомерные массивы в Ruby.
Может кто-нибудь, пожалуйста, дайте мне пример о том, как это сделать?
Возможно, это просто моя нехватка способностей найти здесь эту проблему, но я не могу найти ничего о том, как создавать многомерные массивы в Ruby.
Может кто-нибудь, пожалуйста, дайте мне пример о том, как это сделать?
Строго говоря, в Ruby невозможно создать многомерные массивы. Но можно поместить массив в другой массив, который почти такой же, как многомерный массив.
Вот как вы могли бы создать 2D-массив в Ruby:
a = [[1,2,3], [4,5,6], [7,8,9]]
<ч/" > Как указано в комментариях, вы также можете использовать NArray, который представляет собой библиотеку числовых массивов Ruby:
require 'narray'
b = NArray[ [1,2,3], [4,5,6], [7,8,9] ]
Используйте a[i][j]
для доступа к элементам массива. В основном a[i]
возвращает "вспомогательный массив", сохраненный в позиции i
из a
, и, таким образом, a[i][j]
возвращает номер элемента j
из массива, который хранится в позиции i
.
вы можете передать блок Array.new
Array.new(n) {Array.new(n,default_value)}
значение, возвращающее блок, будет значением каждого индекса первого массива,
поэтому..
Array.new(2) {Array.new(2,5)} #=> [[5,5],[5,5]]
и вы можете получить доступ к этому массиву с помощью array[x][y]
также для второго экземпляра массива, вы также можете передать блок как значение по умолчанию. так
Array.new(2) { Array.new(3) { |index| index ** 2} } #=> [[0, 1, 4], [0, 1, 4]]
Просто уточнение:
arr = Array.new(2) {Array.new(2,5)} #=> [[5,5],[5,5]]
совсем не совпадает с:
arr = Array.new(2, Array.new(2, 5))
в последнем случае попробуйте:
arr[0][0] = 99
и вот что вы получили:
[[99,5], [99,5]]
Есть два способа инициализации мульти-массива (размер 2). Все остальные ответы показывают примеры со значением по умолчанию.
Объявите каждый из подмассива (вы можете сделать это во время выполнения):
multi = []
multi[0] = []
multi[1] = []
или объявите размер родительского массива при инициализации:
multi = Array.new(2) { Array.new }
Пример использования:
multi[0][0] = 'a'
multi[0][1] = 'b'
multi[1][0] = 'c'
multi[1][1] = 'd'
p multi # [["a", "b"], ["c", "d"]]
p multi[1][0] # "c"
Таким образом, вы можете обернуть первый способ и использовать его так:
@multi = []
def multi(x, y, value)
@multi[x] ||= []
@multi[x][y] = value
end
multi(0, 0, 'a')
multi(0, 1, 'b')
multi(1, 0, 'c')
multi(1, 1, 'd')
p @multi # [["a", "b"], ["c", "d"]]
p @multi[1][0] # "c"
Указанный выше метод не работает.
n = 10
arr = Array.new(n, Array.new(n, Array.new(n,0.0)))
arr[0][1][2] += 1
puts arr[0][2][2]
эквивалентно
n = 10
a = Array.new(n,0.0)
b = Array.new(n,a)
arr = Array.new(n, b)
arr[0][1][2] += 1
puts arr[0][2][2]
и будет печатать 1.0, а не 0.0, потому что мы являемся modifiyng array a и печатаем элемент массива a.
На самом деле это намного быстрее, чем метод блока, приведенный выше:
arr = Array.new(n, Array.new(n, Array.new(n,0.0)))
arr[0][1][2] += 1
Мне недавно пришлось воспроизвести многомерный массив PHP-стиля в Ruby. Вот что я сделал:
# Produce PHP-style multidimensional array.
#
# Example
#
# arr = Marray.new
#
# arr[1][2][3] = "foo"
# => "foo"
#
# arr[1][2][3]
# => "foo"
class Marray < Array
def [](i)
super.nil? ? self[i] = Marray.new : super
end
end
Возможно, вы можете смоделировать свой многомерный массив с помощью Hash. Хэш-ключ может быть любым объектом Ruby, поэтому вы также можете взять массив.
Пример:
marray = {}
p marray[[1,2]] #-> nil
marray[[1,2]] = :a
p marray[[1,2]] #-> :a
На основе этой идеи вы можете определить новый класс.
Просто быстрый сценарий:
=begin rdoc
Define a multidimensional array.
The keys must be Fixnum.
The following features from Array are not supported:
* negative keys (Like Array[-1])
* No methods <<, each, ...
=end
class MArray
INFINITY = Float::INFINITY
=begin rdoc
=end
def initialize(dimensions=2, *limits)
@dimensions = dimensions
raise ArgumentError if limits.size > dimensions
@limits = []
0.upto(@dimensions-1){|i|
@limits << (limits[i] || INFINITY)
}
@content = {}
end
attr_reader :dimensions
attr_reader :limits
=begin rdoc
=end
def checkkeys(keys)
raise ArgumentError, "Additional key values for %i-dimensional Array" % @dimensions if keys.size > @dimensions
raise ArgumentError, "Missing key values for %i-dimensional Array" % @dimensions if keys.size != @dimensions
raise ArgumentError, "No keys given" if keys.size == 0
keys.each_with_index{|key,i|
raise ArgumentError, "Exceeded limit for %i dimension" % (i+1) if key > @limits[i]
raise ArgumentError, "Only positive numbers allowed" if key < 1
}
end
def[]=(*keys)
data = keys.pop
checkkeys(keys)
@content[keys] = data
end
def[](*keys)
checkkeys(keys)
@content[keys]
end
end
Это можно использовать как:
arr = MArray.new()
arr[1,1] = 3
arr[2,2] = 3
Если вам нужна предопределенная матрица 2x2, вы можете использовать ее как:
arr = MArray.new(2,2,2)
arr[1,1] = 3
arr[2,2] = 3
#~ arr[3,2] = 3 #Exceeded limit for 1 dimension (ArgumentError)
Я мог представить, как обрабатывать команды типа <<
или each
в двумерном массиве, но не в многомерных.
Это может помочь вспомнить, что массив является объектом в ruby, а объекты (по умолчанию) создаются просто путем их именования или назначения ссылки на объект. Вот процедура создания 3-мерного массива и сброс его на экран для проверки:
def Create3DimensionArray(x, y, z, default) n = 0 # verification code only ar = Array.new(x) for i in 0...x ar[i] = Array.new(y) for j in 0...y ar[i][j] = Array.new(z, default) for k in 0...z # verification code only ar[i][j][k] = n # verification code only n += 1 # verification code only end # verification code only end end return ar end # Create sample and verify ar = Create3DimensionArray(3, 7, 10, 0) for x in ar puts "||" for y in x puts "|" for z in y printf "%d ", z end end end
Вот реализация класса 3D-массива в ruby, в этом случае значение по умолчанию равно 0
class Array3
def initialize
@store = [[[]]]
end
def [](a,b,c)
if @store[a]==nil ||
@store[a][b]==nil ||
@store[a][b][c]==nil
return 0
else
return @store[a][b][c]
end
end
def []=(a,b,c,x)
@store[a] = [[]] if @store[a]==nil
@store[a][b] = [] if @store[a][b]==nil
@store[a][b][c] = x
end
end
array = Array3.new
array[1,2,3] = 4
puts array[1,2,3] # => 4
puts array[1,1,1] # => 0
Использование может также использовать XKeys Gem.
require 'xkeys'
regular = [].extend XKeys::Auto
regular[1,2,3] = 4
# [nil, [nil, nil, [nil, nil, nil, 4]]]
regular[3,2,1, :else=>0] # 0
# Note: regular[1,2] is a slice
# Use regular[1,2,{}] to access regular[1][2]
sparse = {}.extend XKeys::Hash
sparse[1,2,3] = 4
# {1=>{2=>{3=>4}}}
path=[1,2,3]
sparse[*path,{}] # 4