Reputation: 1530
When I have an array (of 1D, 2D, 3D, or more dimensions), I would like to be able to translate an index (from this flatten array) into its coordinates.
For instance, considering *
square:
arr = [ [ [ nil, nil ],
[ nil, nil ],
[ nil, nil ] ],
[ [ "*", nil ],
[ nil, nil ],
[ nil, nil ] ] ]
arr.flatten[6] # => "*"
arr.index2coordinates(6) # => [1,0,0] or [1][0][0]
arr = [ [ [ [ nil, nil ],
[ nil, "*" ],
[ nil, nil ] ] ],
[ [ [ nil, nil ],
[ nil, nil ],
[ nil, nil ] ] ] ]
arr.flatten[3] # => "*"
arr.index2coordinates(3) # => [0,0,1,1] or [0][0][1][1]
arr = [ nil, nil, nil, "*", nil ]
arr.flatten[3] # => "*"
arr.index2coordinates(3) # => [3]
How can we do a such Array#index2coordinates
method? In a sense, this question is the inverse of Convert vector to integer question. Thanks a lot.
Upvotes: 2
Views: 1034
Reputation: 156434
Try a recursive search through the structure building the n-dimensional index as you enter each step, returning the index if/when you find the *
target:
def coord(space, target='*', idx=[])
found = nil
space.each_with_index do |x,i|
found = if x.is_a?(Array)
coord(x, target, idx + [i])
elsif x == target
idx + [i]
end
break found if found
end
found
end
coord(arr3d) # => [1, 0, 0]
coord(arr4d) # => [0, 0, 1, 1]
coord(arr1d) # => [3]
coord([]) # => nil
Upvotes: 0
Reputation: 2517
Examples, step by step:
# 3D array (of [2,3,2] shape)
arr.flatten[6] # => "*"
arr.index2coordinates(6) # => [1,0,0] or [1][0][0]
6 % 2 # => 0
(6 / 2) % 3 # (3) % 3 => 0
((6 / 2) / 3) % 2 # ((3) / 3) %2 => 1 % 2 => 1
# 4D array (of [2,1,3,2] shape)
arr.flatten[3] # => "*"
arr.index2coordinates(3) # => [0,0,1,1] or [0][0][1][1]
3 % 2 # => 1
(3 / 2) % 3 # => 1 % 3 => 1
((3 / 2) / 3) % 1 # => 1 % 1 => 0
(((3 / 2) / 3) / 1) % 2 # 0 % 2 => 0
Simple code for second example
result = []
index = 3
[2,1,3,2].reverse.each do |dimension|
result = [index % dimension] + result
index = (index / dimension)
end
result # => [0, 0, 1, 1]
Upvotes: 3