[英]Calculate average of all data members in a vector of POD struct
I have a sensor that provides 3 different readings.我有一个提供 3 种不同读数的传感器。 I want to read the sensor X times and then get average of all readings:
我想读取传感器 X 次,然后获取所有读数的平均值:
#define NUM_DATA ((int)1000);
struct Data {
int x;
int y;
int z;
}
Data getAverageData() {
static std::vector<Data> vecData(NUM_DATA); // Vector for sensor data
vecData.clear();
for(int i = 0; i < NUM_DATA; i++) {
int x = sensorGetX(); // from sensor
int y = sensorGetY(); // from sensor
int z = sensorGetZ(); // from sensor
vecData[i] = {x, y, z};
}
// I am stuck here!!!
Data average = std::accumulate(vecData.begin(), vecData.end(), 0.0,
[&](int sum, Data d) {
return sum + d.x;
});
return average;
}
The Data
struct is both used for keeping the data in the vector and also the average itself. Data
结构既用于将数据保存在向量中,也用于平均值本身。 I want to keep it this way.我想保持这种状态。 I know of course to do it the oldschool way but I want my code to look smart and I want to use latest facilities that c++11 or c++17 has to offer.
我当然知道要以老式的方式来做,但我希望我的代码看起来很聪明,并且我想使用 c++11 或 c++17 必须提供的最新功能。
constexpr unsigned int num_data = 1000;
struct Data {
int x;
int y;
int z;
}
Data getAverageData() {
Data vecData_temp = {0, 0, 0};
for(size_t i = 0; i < num_data; ++i) {
vecData_temp.x += sensorGetX();
vecData_temp.y += sensorGetY();
vecData_temp.z += sensorGetZ();
}
vecData_temp.x /= num_data;
vecData_temp.y /= num_data;
vecData_temp.z /= num_data;
return vecData_temp;
}
I don't see a point creating a vector in this case.在这种情况下,我看不到创建向量的意义。 tried this light-weight code, only one local variable created.
尝试了这个轻量级代码,只创建了一个局部变量。
Joonroo Taugh's answer is fine; Joonroo Taugh 的回答很好; but, if you wanted to use the latest
c++17
features, I'd go about it like this, you almost had it correct anyway.但是,如果您想使用最新的
c++17
功能,我会像这样使用 go ,无论如何您几乎都正确。
The only issue was you did not set up your collection correctly:唯一的问题是您没有正确设置您的收藏:
push_back
instead of using the subscript operator;push_back
而不是使用下标运算符;reserve
to allocate a block of data all at once, otherwise push_back
will allocate when it runs out of capacity (it only allocates 1.5x more capacity every push_back that exceeds it);reserve
一次性分配一个数据块,否则push_back
会在容量用完时分配(每超过一次push_back只会多分配1.5倍的容量);clear
is good to discard old data when using a static
collection.static
集合时,使用clear
可以很好地丢弃旧数据。 Note: I've added some helper operator overloads to make the average calculation look more math-y and easier to understand.注意:我添加了一些辅助运算符重载,以使平均计算看起来更数学化并且更易于理解。
I would also consider passing in a vector
reference to be filled or returning a local vector instance from the function as part of a std::pair<Data, std::vector<Data>
so you can keep track of the last X
values (which could be its own argument, up to you).我还会考虑传入要填充的
vector
引用或从 function 返回本地向量实例作为std::pair<Data, std::vector<Data>
的一部分,以便您可以跟踪最后的X
值(这可能是它自己的论点,取决于你)。
#include <numeric>
#include <vector>
//Default-construct members so they are not uninitialized.
struct Data {
float x{};
float y{};
float z{};
}
Data operator/(const Data& lhs, float scalar) {
return Data{lhs.x / scalar, lhs.y / scalar, lhs.z / scalar};
}
Data operator+(const Data& lhs, const Data& rhs) {
return Data{x + rhs.x, y + rhs.y, z + rhs.z};
}
Data getAverageData() {
constexpr std::size_t num_data{1000u}; //This could be an argument into the function...
static std::vector<Data> vecData{};
//Clear any data from the previous calculation.
//Does not affect capacity.
vecData.clear();
vecData.reserve(num_data); //Reserve space all at once so push_back doesn't allocate.
for(auto i = std::size_t{0u}; i < num_data; ++i) {
vecData.emplace_back(sensorGetX(), sensorGetY(), sensorGetZ());
}
const auto average = std::accumulate(std::cbegin(vecData), std::cend(vecData), Data{},
[&](Data sum, Data d) {
return sum + (d / static_cast<float>(vecData.size()));
});
return average;
}
Following that if you don't want to use the result vector as a histogram, you can do exactly as Joonroo suggests and just use a temporary variable.之后,如果您不想将结果向量用作直方图,则可以完全按照 Joonroo 的建议进行操作,只需使用临时变量即可。 Using operator overloads makes it much easier though:
不过,使用运算符重载会更容易:
#include <vector>
//Default-construct members so they are not uninitialized.
struct Data {
float x{};
float y{};
float z{};
Data& operator+=(const Data& rhs) {
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
Data& operator/=(float scalar) {
x /= scalar;
y /= scalar;
z /= scalar;
return *this;
}
}
Data operator/(const Data& lhs, float scalar) {
return Data{lhs.x / scalar, lhs.y / scalar, lhs.z / scalar};
}
Data operator+(const Data& lhs, const Data& rhs) {
return Data{x + rhs.x, y + rhs.y, z + rhs.z};
}
Data getAverageData(std::size_t sensor_read_count = 1000) {
Data average{};
for(auto i = std::size_t{0u}; i < sensor_read_count; ++i) {
average += Data{sensorGetX(),sensorGetY(),sensorGetZ()};
}
average /= static_cast<float>(sensor_read_count);
return average;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.