Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run two <algorithm>s side by side on the same input iterator range

If I want to calculate the sum of a bunch of numbers retrieved from an std::istream, I can do the following:

// std::istream & is = ...
int total = std::accumulate(std::istream_iterator<int>(is),
                            std::istream_iterator<int>(),
                            0);

However, if I want to calculate their average, I need to accumulate two different results:

  • the total sum (std::accumulate)
  • the total count (std::distance)

Is there any way to "merge" these two algorithms and run them "side by side" in a single pass of an iterator range? I would like to do something like:

using std::placeholders;
int total, count;
std::tie(total, count) = merge_somehow(std::istream_iterator<int>(is),
                                       std::istream_iterator<int>(),
                                       std::bind(std::accumulate, _1, _2, 0),
                                       std::distance);
double average = (double)total / count;

Is this possible?

like image 446
pyon Avatar asked Dec 10 '13 18:12

pyon


2 Answers

A ready-made solution for this sort of single-pass accumulation is implemented by Boost.Accumulators. You make a single accumulator, say for sum, count and average, populate it, and then extract all three results at the end.

like image 169
Kerrek SB Avatar answered Nov 12 '22 23:11

Kerrek SB


You cannot merge two different algorithms to be interleaved. The algorithms control the flow, and you can only have one flow. Now, in your particular case you can simulate it:

int count = 0;
int total = std::accumulate(std::istream_iterator<int>(is),
                            std::istream_iterator<int>(),
                            0,
                            [&](int x, int y) { ++count; return x+y; });
like image 9
David Rodríguez - dribeas Avatar answered Nov 12 '22 23:11

David Rodríguez - dribeas