簡體   English   中英

在 c++ 中展平一個多維向量

[英]Flatten a multidimensional vector in c++

我想在 c++ 中編寫一個通用的 function 來展平所提供的任何多維向量。 該方法的簽名如下:

template <class U, class T>
void flatten(U* out, T& inp, int* dims, int n){
  // out is the flattened output
  // inp is some multidimensional vector<vector...<U>>
  // dims is an array of the dimensions of inp
  // n is the number of dimensions of inp
  int ticker[n];
  int prodLimit = 1;
  int prod = 0;
  
  // calculate prodLimit as product of elements in dims and initialize ticker
  for (int i=0; i<n; i++){
    ticker[i] = 0;
    prodLimit *= dims[i];
  }
  
  while (prod < prodLimit){
    
    // access the current element in inp
    {...}

    // update ticker
    for (int i=n-1; i>0; i++){
      if (ticker[i] == dims[i]){
        ticker[i] == 0;
        ticker[i-1] += 1;
      }
    }
    prod += 1;
    out[prod] = correctElementIn_inp;
  }
}

除了訪問多維向量inp的特定組件外,大多數操作都很簡單。 由於維度是先驗未知的,我在 while 循環中創建了一個大小為n的數組來處理每個維度的計數器並正確更新它。 現在剩下的唯一問題是使用代碼訪問向量中的正確元素。

例如,假設以下內容成立:

#include <vector>

typedef std::vector<std::vector<double>> vec2;
typedef std::vector<std::vector<std::vector<double>>> vec3;

int main(){
  vec2 inp1 = {...};
  vec3 inp2 = {...};
  
  int s1[2] = {2,3};
  int s2[3] = {2,3,4};
  ...

}

現在這個方法應該能夠同時處理inp1inp2 有沒有一種方法可以遞歸訪問向量元素,而無需為每種情況顯式使用向量元素訪問運算符。

由於手動管理 memory 並手動傳遞大小,您的代碼不必要地復雜。 當您使用std::vector時,兩者都已過時。 即使您確實想要一個原始 C 數組作為結果,您仍然可以使用std::vector並稍后將其內容復制到正確分配的 C 數組。 我會使用遞歸方法:

#include <vector>
#include <iostream>

template <typename E,typename X>
void unroll(const std::vector<E>& v,std::vector<X>& out){
    std::cout << "unroll vector\n";
    out.insert(out.end(), v.begin(), v.end());
}


template <typename V,typename X>
void unroll(const std::vector<std::vector<V>>& v,std::vector<X>& out) {
    std::cout << "unroll vector of vectors\n";
    for (const auto& e : v) unroll(e,out);
}


int main() {
    std::vector<std::vector<std::vector<int>>> x;
    std::vector<int> y;
    x.push_back({{1,2,3},{4,5,6}});
    x.push_back({{7,8,9}});
    unroll(x,y);
    for (const auto& e : y) std::cout << e << " ";
}

Output :

unroll vector of vectors
unroll vector of vectors
unroll vector
unroll vector
unroll vector of vectors
unroll vector
1 2 3 4 5 6 7 8 9 

有沒有一種方法可以遞歸訪問向量元素,而無需為每種情況顯式使用向量元素訪問運算符。

向量元素存儲在連續的 memory 中,因此您可以通過其data()使用指針算法。 但是, std::vector<std::vector<int>>不會將int存儲在連續的 memory 中。只有內部向量元素是連續存儲的,而每個內部向量都會在堆上“某處”分配元素。 沒有訪問x[0][0][0]而不訪問x[0][0]的捷徑。 實際上,如果您想首先使用嵌套向量,我建議您重新考慮。


PS:我有點作弊;)。 我希望在將元素推送到它之前首先計算out的總大小會更好,就像您在代碼中所做的那樣。 為簡潔起見,上面省略了它。 可以使用與上述代碼類似的遞歸來完成。 不是 push to out你會累積一些size直到你到達第一個非向量元素類型。 然后為out預留足夠的空間,然后才運行填充out的實際遞歸。

如果您可以訪問 C++20 編譯器,我會遞歸地使用std::ranges::views::join來制作完全扁平化的視圖。 然后您可以迭代此平面視圖而無需復制任何內容。

using namespace std::ranges;

template<typename R>
concept nested_range = input_range<R> && range<range_reference_t<R>>;

struct flatten_t
{
    template<nested_range R>
    auto operator()(R && r) const
    {
        return std::forward<R>(r) | views::transform(*this) | views::join;
    }
    
    template<typename T>
    auto operator()(T && t) const
    {
        return std::forward<T>(t);
    }
};

template<typename T>
auto operator |(T && t, flatten_t f)
{
    return f(std::forward<T>(t));
}

constexpr flatten_t flatten;

int main() {
    std::vector<std::vector<std::vector<int>>> x;
    x.push_back({{1,2,3},{4,5,6}});
    x.push_back({{7,8,9}});
    for (const auto& e : x | flatten) std::cout << e << " ";
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM