从结构向量中,获取一个向量,该向量收集每个结构的一个字段
From a vector of structs, get a vector that collects one of the fields for every struct
假设我有以下结构:
struct Point {
double X,Y,Z;
};
和以下向量:
std::vector<Point> v;
// populate v with random points
现在,我想调用类似collect(v, X)
的东西,并获取一个包含原始结构向量X
值的std::vector
,例如:
v.push_back(Point{1.0, 2.0, 3.0});
v.push_back(Point{1.1, 0.0, -0.5});
auto ans = collect(v,X);
// ans = [1.0, 1.1]
我认为这是一项非常常见的任务,而且我确信有一个好名字,我在询问时想不出(随时指出我!
我可以这样做:
std::vector<double> collectX(std::vector<Point> v) {
std::vector<double> output;
for (auto elem : v) {
output.push_back(elem.X);
}
}
/* Repeat for each field the struct Point has... */
我知道C++没有反思。我想知道是否有解决方法?正如您可能想象的那样,我正在使用的结构不仅有 3 个字段,因此为每个字段编写一个方法有点令人生畏和不优雅。
所以为每个字段编写一个方法有点令人生畏和不优雅
立即解决此问题的是将字段标识符作为参数传递。
std::vector<double> collect(double Point::* f, std::vector<Point> const& v) {
std::vector<double> output;
for (auto const& elem : v) {
output.push_back(elem.*f);
}
return output;
}
这样称呼:
collect(&Point::X, v);
如果类型并不总是double
,那么上面的内容可以很容易地成为成员类型的模板:
template<typename T>
std::vector<T> collect(T Point::* f, std::vector<Point> const& v) {
std::vector<T> output;
for (auto const& elem : v) {
output.push_back(elem.*f);
}
return output;
}
最后,您正在寻找这种提取的术语是"投影"。即,粗略地说,将函数投影到轴上时会得到什么。在我们的例子中,函数将向量的索引映射到Point
,并且投影位于x
轴上,就像它一样。
它也可以使用 C++ 标准库或 ranges-v3 库即时编写。投影是项目范围的一种非常常见的操作,因此许多以范围为中心的库都有这样做的功能。
使用std::transform
、std::back_inserter
和std::mem_fn
:
#include <functional>
//...
std::vector<Point> v{{0,1,2},{9,8,7}};
std::vector<double> x;
std::transform(v.begin(), v.end(), std::back_inserter(x),
std::mem_fn(&Point::x));
编译器通常可以优化std::mem_fn
背后的间接寻址。
您可以使用std::transform
和std::back_inserter
。
std::vector<Point> v;
v.push_back(Point{1.0, 2.0, 3.0});
v.push_back(Point{1.1, 0.0, -0.5});
std::vector<double> x;
std::transform(v.begin(), v.end(), std::back_inserter(x),
[](Point const& p) -> double { return p.x; });
你可以为这种东西使用模板
template<typename C, typename F>
auto vmap(F f, const C& c) -> std::vector<decltype(f(*c.begin()))> {
std::vector<decltype(f(*c.begin()))> res;
for (auto& x : c) res.push_back(f(x));
return res;
}
用作
auto x_values = vmap([](const Point& p){ return p.x; }, pts);
vmap(f, c)
返回应用于c
元素的任何f
std::vector
,c
是任何标准容器。
要提取我正在使用的x
f
lambda[](const Point& p){ return p.x; }
.
范围 v3 + 宏解决方案,可用于所有字段和类型:
#define view_extract_field(fname) (view::transform([](const auto& val) { return val.fname; }))
auto vx = v | view_extract_field(X) | to_vector;
这不会直接回答您的问题。如果您担心性能,并且需要经常执行此拆分,则考虑不同的存储设计可能会很有用。
class Points {
public:
//Constructor ...
std::vector<double> & getX() const;
private:
std::vector<double> x;
std::vector<double> y;
std::vector<double> z;
};
std::vector<double> & Points::getX() {
return x;
}
通过这种方式,您不必复制点的 x 值(这可能是非常大的内存量),并且您可以快速访问它们。另一方面,缓存一个点的局部性会变得更糟。因此,如果您有性能问题衡量标准,那么这可能是一个想法。
- 将结构向量排序为子组
- 访问存储在向量C++中的结构的多态成员
- NLOHMANN 的 JSON 库将数组转换为结构向量
- 在nlohmann json中,如何将嵌套对象的数组转换为嵌套结构的向量
- 如何在 c++ 中创建结构向量的映射
- 带unique_ptr的结构向量
- C++ - 如何在结构向量中找到结构体一个成员的最大值?
- C++,从文件读取到结构,然后读取到向量(结构被推入向量太多次,而不仅仅是一次)
- 将 int 映射到 C++ 中的向量结构
- 如何在 c++ 中的向量结构中使用结构向量
- 无法将值存储到向量结构中
- 无法将.CSV文件读取为代表向量结构的类
- MPI,C,派生类型,向量结构
- 向量结构的打印成员
- 在 c++ 中对向量<结构 S> 进行二分搜索?
- 不需要删除向量<结构A*>
- 在C++中循环向量结构<string>
- 将字符串放入字符串的向量结构中
- 共享内存中的向量结构
- 我的向量结构没有像预期的那样迭代