在Ruby中创建二维数组并访问子数组


71

我想知道是否有可能创建二维数组并快速访问其中的任何水平或垂直子数组?

我相信在以下情况下我们可以访问水平子数组:

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

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

但是据我了解,我们无法像这样访问它:

x[3..8][6]

我该如何避免或破解此限制?


1
我想x[3..8].each{|a|a[6] = 'something'}这对你来说很丑。
凌晨

Answers:


99

二维Arrays实现方式存在一些问题。

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

HashArray

我更喜欢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,如果我知道我的数据量越来越大,那么我将三思而后行地实现这种多维。


4
这很旧,但是a[2][0]因为尚未创建第三个元素而出现错误?有意义a[1][0]=6吗?我知道这已经很老了……刚才正在看Ruby。
vol7ron

我相信您是正确的@ vol7tron并且a[1][0] = 6可以正常工作。您可以使用a [2]创建第三行,但是直到创建后才能对其进行索引。例如,a[2] = []随后a[2][0] = 6将工作。
圣人,

1
您对[...] almost O(1)[...]表示什么?
2014年

尽管这是一个有趣的解决方案,但是您将使用大量空间来创建数组作为键。对于数字,没有内存分配,但对于数组,有。
sahilbathla 2014年

巧妙的技巧,但是它有一个缺点,您无法通过查看矩阵来推断矩阵的大小。如果您所有的值均为零,那么如果多维数组,您将无法知道大小
Don Giulio

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

至于访问元素,本文非常适合逐步使用您希望的方式封装数组:

如何红宝石阵列


30

您没有说明您的实际目标,但这可能会有所帮助:

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对它进行子类化和扩展。
bta

6
Matrix阅读此答案后,我开始使用它,这很棒。但是,有一个很大的限制,那就是在移动之前最好牢记Matrix-它们是不可变的。因此,没有办法修改单个元素,即m(0, 0) = 0 # => error
gregoltsov 2012年

2
@GregoryGoltsov:+1给Marc-André写作Matrix。至于它们的不变性,我不会称其为限制,而是一个功能。显然,马克·安雷(Marc-Anré)不仅使自己的生活更轻松,而且还以数字的概括形式表示矩阵。
Boris Stitnicky

1
@BorisStitnicky:记录下来,该图书馆的原始作者是Keiju Ishitsuka,而不是我。我也确实需要寻找到使矩阵可变的下一个版本:-)
马克-安德烈·Lafortune

1
@Marc-AndréLafortune:我开始欣赏YPetri :: Simulation类中的不变性,以至于我甚至都重复输入。我在其中使用的Matrix的不变性非常方便。请,如果您使矩阵可变,请确保它们是单独的子类(OpenMatrix例如likeOpenStructStruct),或者确保用户首先必须执行诸如Matrix#openor#unlock或what的操作。
Boris Stitnicky

11

这是一个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数组一样访问每个数组的子节。@data [0..2] [3..5] [8..10] = 0等


6

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吗?大!
gmile

1
问题是:转置为O(n * m),但是在一个方向上检索子数组可以为O(n + m)
johannes

在这里使用collect而不是map添加一些清晰度。
格伦·杰克曼(09年

据我了解,映射和收集是相同的。只是您要为该任务选择的名称。
johannes

2

我很确定这很简单

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]无论如何都会返回
Simone

注意Array.new可以直接使用一个块,不需要mapArray.new(5) {|x| x = [0] } => [[0], [0], [0], [0], [0]]甚至更简单:Array.new(5,[0]) => [[0], [0], [0], [0], [0]]
Alex Moore-Niemi

0
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

-2

这是简单的版本

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

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

8
用这种方法创建的数组引用相同的1维数组,即,更改一个值将影响其他值,例如a [0] [0] = 1将使a [1] [0]也变为1。
凯文C.14年

-3

这是创建“ 2D”数组的简单方法。

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

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

4
这将创建对单个新array(3)的引用的array(3)。这总共是2个数组和1个布尔对象。我想你想要类似的东西m=Array.new(3){Array.new(3, true)}。这将为您提供4个数组和3个布尔对象。
凌晨
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.