Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most 'functional' way to sum pairs of elements from a vector using C++17 or later?

Tags:

c++

c++17

I'd like some suggestions for the most terse and 'functional' way to gather pairs of successive elements from a vector (1st and 2nd, 3rd and 4th, etc.) using modern C++. Assume the vector is of arbitrary but even length. For the examples I'm pulling together, I'm summing the elements of each pair but that's not the main problem. I should add I'll use STL only, no Boost.

In Python I can zip them into 2-tuples via an iterator with

s = range(1,11)
print([(x + y) for x,y in zip(*[iter(s)] * 2)])

In Perl 5 I can peel off pairs with

use List::Util qw/pairs sum/;
use feature 'say';
@s = 1 .. 10;
say sum @$_ foreach (pairs @s);

In Perl 6 I can shove them two at a time into a block with

my @s = 1 .. 10;
for @s -> $x, $y { say $x + $y; }

and in R I can wrap the vector into a 2-column array and sum the rows with

s <- 1:10
print(apply(matrix(s, ncol=2, byrow=TRUE), 1, sum))

I am not fluent in C++ and my solution uses for(;;). That feels too much like C.

#include <iostream>
#include <vector>
#include <numeric>  // std::iota

int main() {
    std::vector<int> s(10);
    std::iota(s.begin(), s.end(), 1);
    for (auto p = s.cbegin(); p != s.cend(); p += 2)
        std::cout << (*p + *(p + 1)) << std::endl;
}

The output of course should be some variant of

3
7
11
15
19
like image 809
Douglas Scofield Avatar asked May 31 '19 15:05

Douglas Scofield


1 Answers

Using range-v3:

for (auto v : view::iota(1, 11) | view::chunk(2)) {
    std::cout << v[0] + v[1] << '\n';
}   

Note that chunk(2) doesn't give you a compile-time-fixed size view, so you can't do:

for (auto [x,y] : view::iota(1, 11) | view::chunk(2)) { ... }
like image 156
Barry Avatar answered Nov 14 '22 22:11

Barry