问题
Knowing the multidimensional-array's shape of a vector, how can we convert it into a new vector of one dimension (by flatten the multidimensional-array)?
For example considering the following array:
arr = [
[
[ nil, nil ],
[ nil, nil ],
[ nil, nil ]
],
[
[ nil, nil ],
[ nil, nil ],
[ nil, nil ]
]
]
arr[0][0][0] = "A"
arr[1][0][1] = "B"
arr # =>
[
[
[ "A", nil ],
[ nil, nil ],
[ nil, nil ]
],
[
[ nil, "B" ],
[ nil, nil ],
[ nil, nil ]
]
]
...where A
is the origin and B
is the destination of the vector. Can write:
shape = [2, 3, 2]
vector = [1, 0, 1]
From now, supposing we flatten arr
, how could we translate the vector? In other words, how to translate this vector of 3 dimensions into a new one of 1 dimension?
This is a special case, because the origin of the vector is also the first coordinate of the array. So we can found the result with:
arr.flatten.index("B") # => 7
Here's a another example with a 2D-array:
arr = [
[ "A", nil ],
[ "B", nil ],
[ nil, nil ],
[ nil, nil ],
[ nil, nil ]
]
We can write this:
shape = [2, 5]
vector = [1, 0]
And, once again,
arr.flatten.index("B") # => 2
But here is a more complicated example, with a negative vector:
arr = [
[ "B", nil ],
[ "A", nil ],
[ nil, nil ],
[ nil, nil ],
[ nil, nil ]
]
shape = [2, 5]
vector = [-1, 0]
How can the following method can be written ?
vector2index(shape, vector) # => -2
An example (simple) with a 1D-array:
arr = [ nil, "B", nil, nil, "A", nil, nil ]
shape = [7]
vector = [-3]
vector2index(shape, vector) # => -3
Is there a simple way to flat a vector from an array of any dimensions? Thanks.
回答1:
First of all, assuming that first element of array is for X axis, second - for Y axis, third - for Z axis, you have a mistake in second and third example. Third example should be
shape = [2,5]
vector = [0,-1]
vector2index(shape, vector) # => -2
And if first element of array is for Y axis, second - for X axis, then 2-nd and 3-rd examples is correct, but the first example is wrong.
If I understand the idea correctly, we need in first example multiply vector[1]
to shape[0]
, multiply vector[2]
to shape[0]*shape[1]
and then calculate sum of 3 elements. Generally, we don't need to multiply 0-th element, and we need to multiply n-th element to shape[0]*shape[1]*...*shape[n-1]
.
You can implement it this way:
vector.each_with_index.map {
|v, i| i == 0? v: v * shape[0..i-1].inject(:*)
}.inject(:+)
Upd. After you updated your question, it becomes more clear. If you want to preserve Ruby's indexing order, you need to reverse both arrays shape
and vector
.
vector.reverse.each_with_index.map {
|v, i| i == 0? v: v * shape[0..i-1].reverse.inject(:*)
}.inject(:+)
来源:https://stackoverflow.com/questions/10392149/convert-vector-to-integer