简体   繁体   English

std :: vector中非整数元素的总和

[英]sum of non-integer elements in std::vector

I was reading following question: How to sum up elements of a C++ vector? 我正在阅读以下问题: 如何总结C ++向量的元素? , and I wanted to use second method ( sum_of_elems =std::accumulate(vector.begin(),vector.end(),0);//#include <numeric> ). ,我想使用第二种方法( sum_of_elems =std::accumulate(vector.begin(),vector.end(),0);//#include <numeric> )。

However, I don't have std::vector<int> , but std::vector<struct packet> . 但是,我没有std::vector<int> ,而是std::vector<struct packet> The packet is defined as following: packet定义如下:

struct packet {
    /// ...
    int length() const;
    ///
}

and I want sum of packet lengths. 我想要数据包长度的总和。

This is what I tried: 这是我试过的:

std::vector<packet> packets;
...
std::accumulate(packets.begin(), packets.end(), 0, [](const packet& a, const packet& b){return a.length() + b.length();});

but it doesn't work. 但它不起作用。 In C#, I'd write something like 在C#中,我会写一些类似的东西

packet[] p;
p.Select(x => p.length()).Sum();

Is it possible to do something like that in C++? 是否有可能在C ++中做类似的事情? I can write method for iterating through the vector and doing it on my own, but I prefer the functional approach where possible. 我可以编写迭代矢量并自己完成的方法,但我更喜欢功能方法。

I would note that the C# implementation is slightly different, in essence. 我注意到C#实现本质上略有不同。

In C++ you are trying to add int and packet whilst in C# you first provide a transformation step from packet to int and then add int s. 在C ++中,您尝试添加intpacket而在C#中,您首先提供从packetint的转换步骤,然后添加int

The equivalent C++, without adaptation: 等效的C ++,没有适应:

std::vector<size_t> lengths; // a length cannot be negative!

std::transform(packets.begin(),
               packets.end(),
               backward_inserter(lengths),
               [](packet const& p) { return p.length(); });

auto const sum = std::accumulate(lengths.begin(), lengths.end(), 0ul);

Of course, it is wasteful to store the intermediate lengths, however it does work out of the box. 当然,存储中间长度是浪费的,但它确实可以开箱即用。

But because we are cool, let us have look at Boost.Range , and more precisely: 但是因为我们很酷,让我们看一下Boost.Range ,更确切地说:

Which have a bit of coolness like Linq: 像Linq一样有点酷:

#include <boost/range/numeric.hpp> // accumulate
#include <boost/range/adaptor/transformed.hpp>

size_t total_size(std::vector<packet> const& packets) {
    return boost::accumulate(
        packets | boost::transformed([](packet const& p) { return p.length(); }),
        0ul);
}

You are accumulating via a binary operation. 您正在通过二进制操作进行累积。 Your accumulated value starts with 0 (an int ), so the left hand side of your binary operation has to be convertible-from 0 -- otherwise, how does it start adding? 您的累计值以0 (一个int )开头,因此二进制操作的左侧必须是可转换的 - 从0 - 否则,它是如何开始添加的?

Try this: 尝试这个:

std::accumulate(
  packets.begin(),
  packets.end(),
  0,
  [](int a, const packet& b){
    return a + b.length();
  }
);

you can also do this via a simple loop: 你也可以通过一个简单的循环来做到这一点:

int acc = 0;
for( const packet& p : packets ) {
  acc += packets.length();
}

The first parameter of the accumulate operation is the running total. 累积操作的第一个参数是运行总计。 In your case, this is an integer, not a packet, so your lambda should be 在你的情况下,这是一个整数,而不是一个数据包,所以你的lambda应该是

[](int a, const packet& b) {return a + b.length();}

The problem is your accumulate function. 问题是你的累积功能。 Its first parameter has to be of the type you're trying to accumulate ( int in this case) and add a value on top of that. 它的第一个参数必须是你试图积累的类型(在这种情况下为int )并在其上添加一个值。

Your lambda function should look like this: [](int currTotal, const packet& b){return currTotal + b.length();} 你的lambda函数应如下所示: [](int currTotal, const packet& b){return currTotal + b.length();}

Apart from lamba, you can change it to 除了lamba,您可以将其更改为

std::accumulate(packets.begin(), packets.end(), 0, packet());

Where you can define functor as: 您可以在哪里定义仿函数:

int operator() (int result, const packet& obj)
{
    return result+ obj.length();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM