[英]Summing struct members inside a vector
考慮以下:
typedef struct {
int a;
int b;
int c;
int d;
} ABCD;
typedef std::vector<ABCD> VecABCD;
假設我想將 VecABCD 類型的向量中的每個“a”成員相加。 簡單! 我只是循環遍歷向量,並在進行時求和。
int CalcSumOfA(const VecABCD &vec)
{
int sumOfA = 0;
VecABCD::const_iterator it;
for(it=vec.begin();it!=vec.end();it++)
sumOfA += it->a;
return sumOfA;
}
說我想用'b'做同樣的事情? 簡單! 我會寫....本質上相同的功能,但只有微不足道的變化。 與“c”和“d”相同。
那么,是否有一種更簡潔、更少重復的方法來做到這一點? 我想做類似的事情:
int sumOfA = SumOfMembers(myVec, a);
但我無法想象如何將這樣的功能放在一起。 理想情況下,它是一個模板,我可以將它與任何類型結構的向量一起使用,而不是專門綁定到 VecABCD。 有人有想法么?
可以使用std::accumulate
完成STL求和
#include <functional>
accumulate(v.begin(), v.end(), 0, bind(plus<int>(), _1, bind(&ABCD::a, _2)))
如果您希望這更通用,可以將tr1 :: function作為要綁定的成員:
int sum_over_vec(const vector<ABCD>& v, const tr1::function<int (const ABCD&)>& member)
{
return accumulate(v.begin(), v.end(),
0,
bind(plus<int>(),
_1,
bind(member, _2)));
};
// ...
int sum_a = sum_over_vec(vec, bind(&ABCD::a, _1));
另一種方法是使用boost :: transform迭代器將邏輯放在迭代器中,而不是將邏輯放在仿函數中:
tr1::function<int (const ABCD&)> member(bind(&ABCD::a, _1));
accumulate(make_transform_iterator(v.begin(), member),
make_transform_iterator(v.end(), member),
0);
編輯添加:C ++ 11 lambda語法
對於C ++ 11 lambdas來說,這變得更加清晰(盡管不幸的是不會更短):
accumulate(v.begin(), v.end(), 0,
[](int sum, const ABCD& curr) { return sum + curr.a });
和
int sum_over_vec(const vector<ABCD>& v, const std::function<int (const ABCD&)>& member)
{
return accumulate(v.begin(), v.end(), 0,
[&](int sum, const ABCD& curr) { return sum + member(curr}); });
};
用法:
// Use a conversion from member function ptr to std::function.
int sum_a = sum_over_vec(vec, &ABCD::a);
// Or using a custom lambda sum the squares.
int sum_a_squared = sum_over_vec(vec,
[](const ABCD& curr) { return curr.a * curr.a; });
另一種選擇是使用指向成員的指針:
int CalcSumOf(const VecABCD & vec, int ABCD::*member)
{
int sum = 0;
for(VecABCD::const_iterator it = vec.begin(), end = vec.end(); it != end; ++it)
sum += (*it).*member;
return sum;
}
...
int sumA = CalcSumOf(myVec, &ABCD::a); // find sum of .a members
int sumB = CalcSumOf(myVec, &ABCD::b); // find sum of .b members
// etc.
你可以使用for_each 。 它是一個選擇。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef struct{
int a;
}ABCD;
typedef vector<ABCD> vecABCD;
struct sum : public unary_function<ABCD, void>
{
sum(){count.a=count.b=count.c=count.d=0;}
void operator() (ABCD x) {
count.a+=x.a;
count.b+=x.b;
count.c+=x.c;
count.d+=x.d;
}
ABCD count;
};
int main()
{
ABCD s1={1,2,3,4};
ABCD s2={5,6,7,8};
vecABCD v;
v.push_back(s1);
v.push_back(s2);
sum s = for_each(v.begin(), v.end(), sum());
cout<<s.count.a<<endl;
}
輸出:
4
使用std :: accumulate :)
讓我們再添加一個選項,遺憾的是一個丑陋的選項。 可以通過offsetof -function從struct ABCD的開頭到它的成員獲取相對地址。 將返回值傳遞給函數,它可以使用每個結構開頭的相對位置進行計數。 如果您的類型可能與int不同,您可能還希望提供sizeof信息。
這可能在未來的 C++ 范圍內成為可能。 因為他們支持預測。
投影允許在迭代類的成員變量上執行算法。
目前(2022) algorithm
庫還沒有一個范圍版本的accumulate
。
有一篇論文可以添加到 C++ 23: P2214: A Plan for C++23 Ranges
但是您已經可以使用它/嘗試使用range v3庫。
#include <iostream>
#include <range/v3/numeric/accumulate.hpp>
struct Point
{
int x;
int y;
};
int main()
{
const auto points = std::vector{ Point{1, 1}, Point{2, 4}, Point{3, 0} };
const int xSum = ranges::accumulate(points, 0, std::plus(), &Point::x);
const int ySum = ranges::accumulate(points, 0, std::plus(), &Point::y);
std::cout << "X sum: " << xSum << " - Y sum: " << ySum << '\n';
// output: X sum: 6 - Y sum: 5
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.