使用 std::accumulate 添加地图的所有值
Adding all values of map using std::accumulate
我只是想添加下面程序中定义的地图的值:
std::map<int, int> floor_plan;
const size_t distance = std::accumulate(std::begin(floor_plan), std::end(floor_plan), 0);
std::cout << "Total: " << distance;
我收到以下错误:
Error C2893: Failed to specialize function template 'unknown-type std::plus::operator ()(_Ty1 &&,_Ty2 &&) const'
std::begin(floor_plan)
为您提供了一个指向 std::map<int, int>::value_type
的迭代器,即 std::pair<const int, int>
。由于没有为该对类型和整数定义 operator+
,因此您的代码无法编译。
选项#1
如果您想对 floor_plan
中的所有映射值求和,您需要提供自己的二元运算符,该运算符能够提取传入的取消引用迭代器的第二个元素:
std::accumulate(std::begin(floor_plan)
, std::end(floor_plan)
, 0
, [] (int value, const std::map<int, int>::value_type& p)
{ return value + p.second; }
);
选项#2
或者,您可以利用 Boost.Iterator 库使用 boost::make_transform_iterator
:
#include <boost/iterator/transform_iterator.hpp>
#include <functional>
auto second = std::mem_fn(&std::map<int, int>::value_type::second);
std::accumulate(boost::make_transform_iterator(std::begin(floor_plan), second)
, boost::make_transform_iterator(std::end(floor_plan), second)
, 0);
选项#3
另一种方法是使用 Boost.Range 库及其自己的 accumulate
算法实现:
#include <boost/range/numeric.hpp>
#include <boost/range/adaptor/map.hpp>
boost::accumulate(floor_plan | boost::adaptors::map_values, 0);
Piotr S. 的回答是正确的,但如果这不是一次性任务,您最好为此类任务制作一个简单方便的仿函数:
struct AddValues
{
template<class Value, class Pair>
Value operator()(Value value, const Pair& pair) const
{
return value + pair.second;
}
};
const size_t distance = std::accumulate(plan.begin(), plan.end(), 0, AddValues());
感谢模板化 operator()
,您可以将此仿函数用于代码中的任何 map
。这很像透明比较器,但这是透明的 "summator".
我不仅会告诉你它是如何工作的。
accumulate
可能的实现如下(因为我们可能从一个基值求和,所以有一个init
值):
template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init,
BinaryOperation op)
{
for (; first != last; ++first) {
init = op(std::move(init), *first); // std::move since C++20
}
return init;
}
所以当我们想要得到一个vector
的sum/product
时,它可能是这样的:
vector<int> vec(5);
std::iota(vec.begin(), vec.end(), 1);
cout<<"vec: ";// output vec
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(cout, ", "));
// vec: 1, 2, 3, 4, 5,
cout<<"\n vec sum is: "<<accumulate(vec.begin(), vec.end(), 0)<<endl;
// vec sum is: 15
cout<<"vec product is: "<<accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>())<<endl;
// vec product is: 120
至于std::map
,你想对map
的第二个值求和,所以你必须在map中得到每个second item
。所以你应该得到 map
中的 value_type
然后得到第二个项目。 map
中的value_type
定义如下:
template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
// using re_tree to sort
typedef Key key_type;
// rb_tree value type
typedef std::pair<key_type, value_type> value_type;
};
例如得到所有second/first
值的总和:
typedef map<string, int> IdPrice;
IdPrice idPrice = {{"001", 100}, {"002", 300}, {"003", 500}};
int sum = accumulate(idPrice.begin(), idPrice.end(), 0, [](int v, const IdPrice::value_type& pair){
return v + pair.second;
// if we want to sum the first item, change it to
// return v + pair.first;
});
cout<<"price sum is: "<<sum<<endl; // price sum is: 900
上面lambda funtion
中的参数v
,存放的是tmp sum,初始值为0。