chappar
chappar

Reputation: 7505

getting dimension of multidimensional array in ruby

I just started learning ruby. Now I need to figure out the dimension of a multidimensional array. I had a look at ruby-docs for the all the array methods, but I could not find a method that returns the dimension.

Here is an example:

For [[1, 2],[3,4],[5,6]] the dimension should be 2.

For [[[1,2],[2,3]],[[3,4],[5]]], the dimension should be 3.

Upvotes: 6

Views: 6811

Answers (6)

thisismydesign
thisismydesign

Reputation: 25054

I was not satisfied with the other solutions so I wrote a one-liner I'd actually use:

def depth(array)
  array.to_a == array.flatten(1) ? 1 : depth(array.flatten(1)) + 1
end

It will flatten the array 1 dimension at the time until it can't flatten anymore, while counting the dimensions.

Why is this better?

  • doesn't require modification to native classes (avoid that if possible)
  • doesn't use metaprogramming (is_a?, send, respond_to?, etc.)
  • fairly easy to read
  • works with hashes as well (notice array.to_a)
  • actually works (unlike only checking the first branch, and other silly stuff)

Upvotes: 0

Ivaylo Strandjev
Ivaylo Strandjev

Reputation: 70931

There is not a built-in function for that as there may be multiple definition as to what you mean by "dimension" for an array. Ruby's arrays may contain anything including hashes or other arrays. That's why I believe you need to implement your own function for that.

Asuming that by dimension you mean "the deepest nested level of arrays" this should do the trick:

def get_dimension a
  return 0 if a.class != Array
  result = 1
  a.each do |sub_a|
    if sub_a.class == Array
      dim = get_dimension(sub_a)
      result = dim + 1 if dim + 1 > result
    end
  end
  return result
end

EDIT: and as ruby is a great language and allows you to do some fancy stuff you can also make get_dimension a method of Array:

 class Array
   def get_dimension
   ... # code from above slightly modified
   end
 end

Upvotes: 3

bmorgan
bmorgan

Reputation: 525

As a modification of Tass's approach:

class Array
    def depth
        map{ |element| element.is_a?( Vector ) ? element.depth + 1 : 1 }.max 
    end
end

Keeps depth as a method of Array, and doesn't require adding a method to Object.

Of course, that might be what you want if you are going to call my_object.depth, where you don't know in advance that my_object.class == Array

Upvotes: 0

Reactormonk
Reactormonk

Reputation: 21690

Simple, object-oriented solution.

class Array
  def depth
    map {|element| element.depth + 1 }.max
  end
end

class Object
  def depth
    0
  end
end

Upvotes: 6

pguardiario
pguardiario

Reputation: 54984

How about:

class Object
    def dimension
        self.class == Array ? 1 + self[0].dimension : 0
    end
end
[[[1,2],[2,3]],[[3,4],[5]]].dimension
#=> 3

Upvotes: 0

fl00r
fl00r

Reputation: 83680

in the simplest case

depth = Proc.new do |array|
  depth = 1
  while Array === array.first do
    array = array.first
    depth += 1
  end
  depth
end

array =  [[[1,2],[2,3]],[[3,4],[5]]]    
depth.call(array)
#=> 3

Or this tiny recursive method

def depth(array, depth=1)
  array = array.send(:first)
  Array === array ? depth(array, depth+1) : depth
end

array =  [[[1,2],[2,3]],[[3,4],[5]]]    
depth(array)
#=> 3

Upvotes: 1

Related Questions