在 Ruby 中创建二维数组和访问子数组
Posted
技术标签:
【中文标题】在 Ruby 中创建二维数组和访问子数组【英文标题】:Create two-dimensional arrays and access sub-arrays in Ruby 【发布时间】:2010-12-15 19:26:01 【问题描述】:我想知道是否有可能创建一个二维数组并快速访问其中的任何水平或垂直子数组?
我相信我们可以在以下情况下访问水平子数组:
x = Array.new(10) Array.new(20)
x[6][3..8] = 'something'
但据我了解,我们不能这样访问它:
x[3..8][6]
如何避免或破解此限制?
【问题讨论】:
我猜x[3..8].each|a|a[6] = 'something'
对你来说太丑了。
【参考方案1】:
二维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
。
【讨论】:
这是旧的但a[2][0]
是一个错误,因为第三个元素尚未创建?意思是a[1][0]=6
会起作用吗?我知道这很老了......现在正在看 Ruby。
我相信你是正确的@vol7tron 和a[1][0] = 6
确实有效。您可以使用 a[2] 创建第三行,但在创建它之前不能索引到它。例如,a[2] = []
后跟 a[2][0] = 6
将起作用。
你说的 [...] almost O(1)
[...] 是什么意思?
虽然它是一个有趣的解决方案,但您将使用大量空间来创建数组作为键。对于数字没有内存分配,但对于数组有。
巧妙的技巧,但它有一个缺点,您无法通过查看矩阵来推断矩阵的大小。如果您的所有值都为零,则您无法知道多维数组的大小【参考方案2】:
这是创建“二维”数组的简单方法。
2.1.1 :004 > m=Array.new(3,Array.new(3,true))
=> [[true, true, true], [true, true, true], [true, true, true]]
【讨论】:
这会创建一个数组 (3),其中包含对 单个 新数组 (3) 的引用。总共有 2 个数组和 1 个布尔对象。我想你想要像m=Array.new(3)Array.new(3, true)
这样的东西。这将为您提供 4 个数组和 3 个布尔对象。【参考方案3】:
我很确定这很简单
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
【讨论】:
您不必指定x
,因为无论如何都会返回[0]
注意Array.new
可以直接取块,不需要map
:Array.new(5) |x| x = [0]
=> [[0], [0], [0], [0], [0]]
或者更简单:Array.new(5,[0])
=> [[0], [0], [0], [0], [0]]
【参考方案4】:
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
【讨论】:
【参考方案5】:这是简单的版本
#one
a = [[0]*10]*10
#two
row, col = 10, 10
a = [[0]*row]*col
【讨论】:
这种方式创建的数组是指同一个一维数组,即改变一个值会影响另一个值,例如a[0][0] = 1会变成a[1][ 0] 也变成 1。【参考方案6】:rows, cols = x,y # your values
grid = Array.new(rows) Array.new(cols)
至于访问元素,这篇文章非常适合一步一步地以您想要的方式封装数组:
How to ruby array
【讨论】:
【参考方案7】:您没有说明您的实际目标,但也许这会有所帮助:
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]]
【讨论】:
如果您需要额外的功能或更喜欢使用x[6][3..8]
表示法,您始终可以继承Matrix
并对其进行扩展。
我在阅读此答案后开始使用Matrix
,这很棒。但是,在转到Matrix
之前最好记住一个很大的限制——它们是不可变的。所以,没有办法修改单个元素,即m(0, 0) = 0 # => error
@GregoryGoltsov:+1 给 Marc-André 写Matrix
。至于它们的不变性,我不会称之为限制,而是一种特性。显然,Marc-Anré 不仅让他自己的生活更轻松,而且还将矩阵呈现为数字的概括。
@BorisStitnicky:为了记录,图书馆的原作者是 Keiju Ishitsuka,而不是我。我还真的需要考虑为下一个版本制作可变矩阵:-)
@Marc-AndréLafortune:我开始欣赏我的YPetri::Simulation class 的不变性,以至于我什至重复了输入。我在其中使用的 Matrix 的不变性很方便。如果您使矩阵可变,请确保它们是单独的子类(例如OpenMatrix
,例如OpenStruct
和Struct
),或者用户首先必须执行Matrix#open
或@987654334 之类的操作@ 或者什么。【参考方案8】:
这是一个 3D 数组案例
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 数组一样访问每个数组的子部分。 @数据[0..2][3..5][8..10] = 0 等等
【讨论】:
【参考方案9】: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]
【讨论】:
哦,数组继承了transpose
?太好了!
这样的问题是:转置是O(n*m),但是取一个方向的子数组可以是O(n+m)
使用 collect
而不是 map
在这里增加了一点清晰度。
据我了解,map 和 collect 是一样的。这只是您喜欢此任务的名称。以上是关于在 Ruby 中创建二维数组和访问子数组的主要内容,如果未能解决你的问题,请参考以下文章