6

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.

6 Answers 6

6

Simple, object-oriented solution.

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

class Object
  def depth
    0
  end
end
Sign up to request clarification or add additional context in comments.

Comments

3

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

Comments

1

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

6 Comments

Why proc, not regular function?
I am not sure, doc %) It is behavior-driven stuff. I was in the console and I usually use procs in console. Of course it could be rewritten as an usual method
I'm just curious, that's all :)
I think this will not work for instance in such a case: a = [1, [2,3]]. The output of your function will be 1 while in fact I believe we want to get 2.
I believe he is talking about "matrix"
|
0

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

2 Comments

again this will not work in the case a = [3, [1,2]]. The output will be 1 instead of 2. A slight modification will make it work for that case, though.
@izomorphius - It seems to me that 1 is the right value in that case. You're right that the question doesn't make it clear though.
0

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

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.