ArafatK - 4 months ago 14
Ruby Question

# Simple Way to Check if the Ruby array is a matrix?

I am working on a project that involves checking if the input is a n-dimensional matrix(and find its dimensions) and raise error if not. For example

``````arr = [ [[1,2],[3,4]], [[5,6],[7,8]], [[9,10],[11,12]] ]
``````

is a matrix of dimensions [3 2 2]. What would be the simplest generic way to do that ?

A recursive solution, but not pretty easy to understand.

``````arr1 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]
arr2 = [[[1, 2], [4]], [6, [7, 8]]]

def dimensions(m)
if m.any? { |e| e.is_a?(Array) }
d = m.group_by { |e| e.is_a?(Array) && dimensions(e) }.keys
[m.size] + d.first if d.size == 1 && d.first
else
[m.size]
end
end

dimensions(arr1)  #=> [3, 2, 2]
dimensions(arr2)  #=> nil
``````

Explaination

The algorithm checks first for nested arrays, `m.any? { |e| e.is_a?(Array) }`. If there aren't nested arrays then you have just one dimension and it returns the size of the given array via `[m.size]` within the `else` block.

``````dimensions([1,2,3])  #=> [3]
``````

If there is at least one nested array then you have to ensure that all elements are arrays and the arrays itself have the same dimensions. This check is done via `d = m.group_by { |e| e.is_a?(Array) && dimensions(e) }.keys` with groups all elements by its dimensions.

``````[[5, 6], [7, 8]].group_by { |e| ... }.keys
#=> [[2]], all nested array dimensions are equal [2]
[[1, 2], [4]].group_by { |e| ... }.keys
#=> [[1], [2]], different dimensions
[6, [7, 8]].group_by { |e| ... }.keys
#=> [false, [2]], an element isn't an array
``````

The algorithm takes only the valid results of the `group_by` with `if d.size == 1 && d.first` and adds the dimensions of the nested arrays to the result via `[m.size] + d.first`. If there are more than one key element or only `nil` which means all nested arrays are invalid then it returns `nil` implicitly.

That's all.