Ruby multidimensional array

RubyMultidimensional Array

Ruby Problem Overview


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 someone please give me an example on how to do it?

Ruby Solutions


Solution 1 - Ruby

Strictly speaking it is not possible to create multi dimensional arrays in Ruby. But it is possible to put an array in another array, which is almost the same as a multi dimensional array.

This is how you could create a 2D array in Ruby:

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


As stated in the comments, you could also use NArray which is a Ruby numerical array library:

require 'narray'
b = NArray[ [1,2,3], [4,5,6], [7,8,9] ]


Use a[i][j] to access the elements of the array. Basically a[i] returns the 'sub array' stored on position i of a and thus a[i][j] returns element number j from the array that is stored on position i.

Solution 2 - Ruby

you can pass a block to Array.new

Array.new(n) {Array.new(n,default_value)}

the value that returns the block will be the value of each index of the first array,

so..

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

and you can access this array using array[x][y]

also for second Array instantiation, you can pass a block as default value too. so

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

Solution 3 - Ruby

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

Solution 4 - Ruby

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"

Solution 5 - Ruby

The method given above don't works.

n = 10
arr = Array.new(n, Array.new(n, Array.new(n,0.0))) 
arr[0][1][2] += 1
puts arr[0][2][2]

is equivalent to

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]

and will print 1.0, not 0.0, because we are modifiyng array a and printing the element of array a.

Solution 6 - Ruby

Actually this is much quicker than the block method given above:

arr = Array.new(n, Array.new(n, Array.new(n,0.0))) 

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

Solution 7 - Ruby

I had to reproduce PHP-style multidimensional array in Ruby recently. Here is what I did:

# 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

Solution 8 - Ruby

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.

Solution 9 - Ruby

It might help to remember that the array is an object in ruby, and objects are not (by default) created simply by naming them or naming a the object reference. Here is a routine for creating a 3 dimension array and dumping it to the screen for verification:

def Create3DimensionArray(x, y, z, default)
n = 0                       # verification code only
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 		# verification code only
ar[i][j][k] = n # verification code only
n += 1          # verification code only
end                 # verification code only
end
end
return ar
end

Create sample and verify

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

Solution 10 - Ruby

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionandkjaerView Question on Stackoverflow
Solution 1 - RubyVegerView Answer on Stackoverflow
Solution 2 - RubyOrlandoView Answer on Stackoverflow
Solution 3 - RubyXavier NayracView Answer on Stackoverflow
Solution 4 - RubyEvmorovView Answer on Stackoverflow
Solution 5 - RubykiparView Answer on Stackoverflow
Solution 6 - RubyKri-banView Answer on Stackoverflow
Solution 7 - RubyDamian BorowskiView Answer on Stackoverflow
Solution 8 - RubyknutView Answer on Stackoverflow
Solution 9 - RubymhdecourseyView Answer on Stackoverflow
Solution 10 - RubyedymerchkView Answer on Stackoverflow