在 C++ 中展平多维向量
Flatten a multidimensional vector in c++
我想用 C++ 编写一个通用函数来展平所提供的任何多维向量。方法签名如下:
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};
...
}
现在这个方法应该可以同时处理inp1
和inp2
。
有没有一种方法可以递归访问向量元素,而无需为每种情况显式使用向量元素访问运算符。
由于手动管理内存和手动传递大小,您的代码不必要地复杂。当您使用 std::vector
时,两者都已过时。即使您确实想要一个原始的 C-array 作为结果,您仍然可以使用 std::vector
并稍后将其内容复制到正确分配的 C-array。我会使用递归方法:
#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 << " ";
}
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
Is there a way of recursively accessing the vector elements without explicitly using the vector element access operator for each case.
A 向量元素存储在连续内存中,因此您可以通过其 data()
使用指针算法。但是,std::vector<std::vector<int>>
不会将 int
存储在连续的内存中。只有内部向量元素是连续存储的,而每个内部向量在堆上“某处”分配元素。不访问 x[0][0]
就没有访问 x[0][0][0]
的捷径。实际上,如果您想首先使用嵌套向量,我建议您重新考虑。
PS:我有点作弊 ;)。我希望在将元素推送到它之前先计算 out
的总大小会更高效,就像您在代码中所做的那样。为简洁起见,上面省略了它。可以使用与上述代码类似的递归来完成。而不是 pusing out
你会积累一些 size
直到你达到第一个 non-vector 元素类型。然后预先为 out
预留足够的 space,然后才 运行 填充 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 << " ";
}
我想用 C++ 编写一个通用函数来展平所提供的任何多维向量。方法签名如下:
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};
...
}
现在这个方法应该可以同时处理inp1
和inp2
。
有没有一种方法可以递归访问向量元素,而无需为每种情况显式使用向量元素访问运算符。
由于手动管理内存和手动传递大小,您的代码不必要地复杂。当您使用 std::vector
时,两者都已过时。即使您确实想要一个原始的 C-array 作为结果,您仍然可以使用 std::vector
并稍后将其内容复制到正确分配的 C-array。我会使用递归方法:
#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 << " ";
}
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
Is there a way of recursively accessing the vector elements without explicitly using the vector element access operator for each case.
A 向量元素存储在连续内存中,因此您可以通过其 data()
使用指针算法。但是,std::vector<std::vector<int>>
不会将 int
存储在连续的内存中。只有内部向量元素是连续存储的,而每个内部向量在堆上“某处”分配元素。不访问 x[0][0]
就没有访问 x[0][0][0]
的捷径。实际上,如果您想首先使用嵌套向量,我建议您重新考虑。
PS:我有点作弊 ;)。我希望在将元素推送到它之前先计算 out
的总大小会更高效,就像您在代码中所做的那样。为简洁起见,上面省略了它。可以使用与上述代码类似的递归来完成。而不是 pusing out
你会积累一些 size
直到你达到第一个 non-vector 元素类型。然后预先为 out
预留足够的 space,然后才 运行 填充 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 << " ";
}