Convert vector to integer

2019-06-09 06:53发布

问题:

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(:+)