【问题标题】:sum of non-integer elements in std::vectorstd::vector 中非整数元素的总和
【发布时间】:2013-08-17 16:10:45
【问题描述】:

我正在阅读以下问题: How to sum up elements of a C++ vector?,我想使用第二种方法(sum_of_elems =std::accumulate(vector.begin(),vector.end(),0);//#include <numeric>)。

但是,我没有std::vector<int>,而是std::vector<struct packet>packet 定义如下:

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

我想要数据包长度的总和。

这是我尝试过的:

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

但它不起作用。在 C# 中,我会写类似的东西

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

在 C++ 中可以做类似的事情吗?我可以编写遍历向量的方法并自己完成,但我更喜欢函数式方法。

【问题讨论】:

    标签: c++ vector stl functional-programming


    【解决方案1】:

    您正在通过二元运算累积。你的累加值以0(一个int)开头,所以你的二进制操作的左边必须是可转换的——来自0——否则,它如何开始添加?

    试试这个:

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

    你也可以通过一个简单的循环来做到这一点:

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

    【讨论】:

    • 另一个解决方案很好,但简单的循环似乎可以解释一切,而不需要读者付出太多努力。 +1
    【解决方案2】:

    问题是您的累积功能。它的第一个参数必须是您尝试累积的类型(在本例中为int)并在其上添加一个值。

    您的 lambda 函数应如下所示:[](int currTotal, const packet&amp; b){return currTotal + b.length();}

    【讨论】:

      【解决方案3】:

      累加操作的第一个参数是累计。在你的情况下,这是一个整数,而不是一个数据包,所以你的 lambda 应该是

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

      【讨论】:

        【解决方案4】:

        除了lamba,可以改成

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

        您可以将仿函数定义为:

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

        【讨论】:

        • 这可行,但是将packet 加倍作为累积函子有点奇怪——如果复制成本高(或者可能不可能),这也是个坏主意。为什么不使用特定的仿函数类,例如问题中的 lambda?
        【解决方案5】:

        我会注意到 C# 实现在本质上略有不同。

        在 C++ 中,您尝试添加 intpacket,而在 C# 中,您首先提供从 packetint 的转换步骤,然后添加 ints。

        等价的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);
        

        当然,存储中间长度很浪费,但它确实可以开箱即用。

        但是因为我们很酷,让我们看看Boost.Range,更准确地说:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-18
          • 1970-01-01
          • 2014-06-13
          • 2011-12-27
          • 2018-01-11
          • 1970-01-01
          • 1970-01-01
          • 2016-09-21
          相关资源
          最近更新 更多