Ruby多维数组

53

也许只是我能力不足,在这里找到有关如何在Ruby中创建多维数组的内容,但我找不到任何信息。

请问有人可以给我一个如何创建多维数组的示例吗?

10个回答

45

严格来说,Ruby 不支持创建多维数组。但是可以将一个数组放入另一个数组中,这与多维数组几乎相同。

以下是在 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]返回存储在a的第i个位置的“子数组”,因此a[i][j]返回存储在ai个位置的数组中的第j个元素。

6
作为科学计算/密集数据的替代方案,可以考虑使用NArray或编码方法。 - user166390
3
需要注意的是,访问它的语法是 a[1][2][1] 而不是一些人可能期望的 a[1,2,1] - tadman
@veger 我怎么从那个数组中获取值? - andkjaer
尝试使用这个类:Matrix,并查看Hal Fulton撰写的非常有用的文章:在Ruby中操作结构化数据 - mjnissim
如果您需要更改矩阵中的值,那么Matrix类并不是很好。这些条目是不可变的。 - Vass
显示剩余4条评论

23

你可以将一个块传递给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]]

当使用这种方式初始化时,您不需要指定数组的大小。myArray = Array.new{Array.new} 可以很好地初始化一个空数组,准备将其他数组推入其中。 - emery
1
@emery 给出的示例很危险:不能对这样的数组进行索引:(Array.new{Array.new})[2][2] = :value # => NoMethodError: undefined method '[]=' for nil:NilClass - Patrick

11

仅仅是澄清一下:

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]]

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"

3
上面提供的方法不起作用。
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,因为我们修改了数组a并打印出数组a的元素。


1

最近我需要在Ruby中复制PHP风格的多维数组。以下是我的做法:

# 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

1
实际上,这种方法比上面提供的块状方法要快得多:
arr = Array.new(n, Array.new(n, Array.new(n,0.0))) 

arr[0][1][2] += 1

1
@Kri-ban的示例是不正确的。嵌套数组并不是所有新对象,而是在单元格之间共享,例如:a = Array.new(2, Array.new(2, 0.0)); a[0][1] = 5; a # => [[0.0, 5], [0.0, 5]]即使只设置了一次,5也会出现在索引[0][1][1][1]处。 - Patrick

0
这是一个在 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

0

记住数组是 Ruby 中的一个对象,而对象不是(默认情况下)通过简单地命名它们或命名对象引用来创建的。以下是一个创建三维数组并将其转储到屏幕以进行验证的例程:

def Create3DimensionArray(x, y, z, default)
    n = 0                       # 仅用于验证的代码
    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      # 仅用于验证的代码
                ar[i][j][k] = n # 仅用于验证的代码
                n += 1          # 仅用于验证的代码
            end                 # 仅用于验证的代码
        end
    end
    return ar
end
# 创建样本并验证 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

更好的验证码:<pre>for x in 0...ar.length for y in 0...ar[x].length for z in 0...ar[x][y].length printf "%3d ", ar[x][y][z] end puts "|" end puts "--" end </pre> - mhdecoursey

0
也许您可以使用哈希表来模拟多维数组。哈希表的键可以是任何 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矩阵,可以使用以下代码:

matrix = [[1, 2], [3, 4]];

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,但是在多维数组中就不太清楚了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接