Ruby multidimensional array

前端 未结 11 1357
春和景丽
春和景丽 2020-11-28 09:30

Maybe it\'s just my lack of abilities to find stuff here that is the problem, but I can\'t find anything about how to create multidimensional arrays in Ruby.

Could s

相关标签:
11条回答
  • 2020-11-28 09:52

    Perhaps you can simulate your multidimensional Array with a Hash. The Hash-key can by any Ruby object, so you could also take an array.

    Example:

    marray = {}
    p marray[[1,2]]   #-> nil
    marray[[1,2]] = :a
    p marray[[1,2]]   #-> :a
    

    Based on this idea you could define a new class.

    Just a quick scenario:

    =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
    

    This can be used as:

    arr = MArray.new()
    arr[1,1] = 3
    arr[2,2] = 3
    

    If you need a predefined matrix 2x2 you can use it as:

    arr = MArray.new(2,2,2)
    arr[1,1] = 3
    arr[2,2] = 3
    #~ arr[3,2] = 3  #Exceeded limit for 1 dimension (ArgumentError)
    

    I could imagine how to handle commands like << or each in a two-dimensional array, but not in multidimensional ones.

    0 讨论(0)
  • 2020-11-28 09:52

    Here is an implementation of a 3D array class in ruby, in this case the default value is 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 讨论(0)
  • 2020-11-28 09:53

    There are two ways to initialize multi array (size of 2). All the another answers show examples with a default value.

    Declare each of sub-array (you can do it in a runtime):

    multi = []
    multi[0] = []
    multi[1] = []
    

    or declare size of a parent array when initializing:

    multi = Array.new(2) { Array.new }
    

    Usage example:

    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"
    

    So you can wrap the first way and use it like this:

    @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"
    
    0 讨论(0)
  • 2020-11-28 09:55

    Use can also use the 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
    
    0 讨论(0)
  • 2020-11-28 09:57

    Just a clarification:

    arr = Array.new(2) {Array.new(2,5)} #=> [[5,5],[5,5]]
    

    is not at all the same as:

    arr = Array.new(2, Array.new(2, 5))
    

    in the later case, try:

    arr[0][0] = 99
    

    and this is what you got:

    [[99,5], [99,5]]
    
    0 讨论(0)
提交回复
热议问题