【问题标题】:Ruby multidimensional arrayRuby 多维数组
【发布时间】:2011-10-24 06:01:13
【问题描述】:

也许问题在于我缺乏在这里找到东西的能力,但我找不到任何关于如何在 Ruby 中创建多维数组的信息。

谁能给我一个例子来说明如何做到这一点?

【问题讨论】:

    标签: ruby multidimensional-array


    【解决方案1】:

    严格来说,在 Ruby 中创建多维数组是不可能的。但是可以把一个数组放到另外一个数组里面,和多维数组差不多。

    这是在 Ruby 中创建二维数组的方法:

    a = [[1,2,3], [4,5,6], [7,8,9]]
    


    如 cmets 中所述,您还可以使用 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] 从存储在位置i 的数组中返回元素编号j

    【讨论】:

    • 作为替代方案(用于科学计算/密集数据),请考虑 NArray 或编码方法。
    • 重要的是要注意访问它的语法是 a[1][2][1] 而不是 a[1,2,1],正如某些人所期望的那样。
    • @veger 如何从该数组中获取值?
    • @andkjaer:tadman 已经提到过,但我用一些关于它的工作原理的额外细节扩展了我的答案。
    • 这可以扩展到多维数组> dim 2。例如my3Darray=[[[1,2,3],[4,5,6]],[['a','b','c'],['d','e','fgh']] ];将 my3Darray[1][1][2][1]
    【解决方案2】:

    您可以将块传递给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 实例化,您也可以将一个块作为默认值传递。所以

    Array.new(2) { Array.new(3) { |index| index ** 2} } #=> [[0, 1, 4], [0, 1, 4]]
    

    【讨论】:

    • 这种方式初始化时不需要指定数组的大小。 myArray = Array.new{Array.new} 可以很好地初始化一个准备好将数组推入其中的空数组。
    • @emery 给出的例子很危险:不能索引到这样的数组:(Array.new{Array.new})[2][2] = :value # => NoMethodError: undefined method '[]=' for nil:NilClass
    【解决方案3】:

    只是一个澄清:

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

    【讨论】:

      【解决方案4】:

      有两种方法可以初始化多数组(大小为 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"
      

      【讨论】:

        【解决方案5】:

        上面给出的方法不起作用。

        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 的元素。

        【讨论】:

          【解决方案6】:

          其实这比上面给出的block方法快很多:

          arr = Array.new(n, Array.new(n, Array.new(n,0.0))) 
          
          arr[0][1][2] += 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] 上,即使它只设置了一次。
          【解决方案7】:

          我最近不得不在 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
          

          【讨论】:

            【解决方案8】:

            也许您可以使用哈希来模拟您的多维数组。 Hash-key 可以是任何 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)
            

            我可以想象如何在二维数组中处理诸如&lt;&lt;each 之类的命令,而不是在多维数组中。

            【讨论】:

              【解决方案9】:

              记住数组是 ruby​​ 中的对象可能会有所帮助,并且对象不是(默认情况下)通过命名它们或命名对象引用来创建的。下面是一个创建 3 维数组并将其转储到屏幕进行验证的例程:

              def Create3DimensionArray(x, y, z, 默认) n = 0 # 仅验证码 ar = Array.new(x) 对于我在 0...x ar[i] = Array.new(y) 对于 j 在 0...y ar[i][j] = Array.new(z, 默认值) for k in 0...z # 仅验证码 ar[i][j][k] = n # 仅验证码 n += 1 # 仅验证码 end # 仅验证码 结尾 结尾 返回 结尾 # 创建样本并验证 ar = Create3DimensionArray(3, 7, 10, 0) 对于 x 在 ar 放“||” 对于 x 中的 y 放“|” 对于 z in y printf "%d", z 结尾 结尾 结束

              【讨论】:

              • 更好的验证码:
                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 
              【解决方案10】:

              这是一个 ruby​​ 中的 3D 数组类的实现,在这种情况下,默认值为 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
              

              【讨论】:

                猜你喜欢
                • 2012-12-05
                • 1970-01-01
                • 2018-02-25
                • 2011-11-29
                • 2015-09-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多