ArafatK - 1 year ago 51

Ruby Question

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 ?

Answer Source

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.