简体   繁体   中英

How to flatten a 3D array where the 3d dimension is not fixed size into 1D array?

Given a 2D array where each (x,y) cell contains a vector of strings (for simplicity) of different size.

What's the most efficient way to flatten this data structure into 1D array, ie creating a function mapping injectively each string to {1,...,n} where n is the total number of strings in the data structure.

You can map an index i, j, k to linear position p in O(1) and back in O(log N), where N is the size of the 2D array, not the total number of strings.

First, let's treat your 2D array as a 1D, since that just makes things much easier. Index i is the index of a vector in the array. Index k is the position of a string in the vector. N is the size of the array.

You can create an array of integers (eg size_t ) that holds the zero-based cumulative sum of all the vector lengths:

lengths = array[N]
lengths[0] = 0
for(i = 1 to N)
    lengths[i] = lengths[i - 1] + size(array[i - 1])

If you want, you can compute the total number of strings as total = lengths[N - 1] + size(array[N - 1]) .

Now, for a given string at index i, k , the position in the expanded array is just

p = lengths[i] + k

Given a position p , you map it to i, k using a bisection algorithm (binary search that returns the index of the left bound when an exact match isn't found):

i = bisect(lengths, p)
k = p - lengths[i]

Bisection is a simplified binary search, so O(log N).

All this works very nicely until you start expanding your vectors. At that point, insertion and deletion become O(N) operations, since you need to increment or decrement all the cumulative sums past the insertion point. To insert:

array[i][k].push(a_string)
for(z = i + 1 to N)
    lengths[z]++

And to delete:

array[i][k].pop()
for(z = i + 1 to N)
    lengths[z]--

By the way, if you still want to use indices x, y for the array, you can convert between the linear index i of lengths and back using

i = x + C * y
x = i % C
y = i / C

Here, C is the number of columns in your array. You can easily generalize this to any number of dimensions.

Doesn't simple direct way work for you?

#include <vector>
#include <string>

int main() {
        std::vector<std::string> omg[3][4];
        std::vector<std::string> rv;
        for(auto const &row: omg) {
                for(auto const &cell: row) {
                        for(auto const &str: cell) {
                                rv.push_back(str);
                        }
                }
        }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM