在向量内汇总结构成员

时间:2009-06-23 04:22:55

标签: c++ stl

请考虑以下事项:

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。有人有什么想法吗?

5 个答案:

答案 0 :(得分:14)

STL摘要可以使用std::accumulate

完成
#include <functional>

accumulate(v.begin(), v.end(), 0, bind(plus<int>(), _1, bind(&ABCD::a, _2)))

如果您希望这更通用,可以将tr1 ::函数带到要绑定的成员:

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 iterator将逻辑放在迭代器中:

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; });

答案 1 :(得分:10)

另一种选择是使用指向成员的指针:

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.

答案 2 :(得分:1)

您可以使用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

答案 3 :(得分:1)

使用std::accumulate:)

答案 4 :(得分:0)

让我们再添加一个选项,遗憾的是一个丑陋的选项。可以通过offsetof -function从struct ABCD的开头到它的成员获取相对地址。将返回值传递给函数,它可以使用每个结构开头的相对位置进行计数。如果您的类型可能与int不同,您可能还希望提供sizeof信息。