2013-12-10 14 views
9

Jeśli chcę, aby obliczyć sumę pęczek liczb pobranych z std::istream, mogę wykonać następujące czynności:Run dwa <algorithm> s obok siebie w tym samym przedziale iteracyjnej wejściowe

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

Jednak gdybym aby obliczyć ich średnią, muszę zgromadzić dwa różne wyniki:

  • suma (std::accumulate)
  • łączna liczba (std::distance)

Czy istnieje jakiś sposób, aby „połączyć” Te dwa algorytmy i uruchomić je „obok siebie” w jednym przejściu z zakresu iteracyjnej? Chciałbym zrobić coś takiego:

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; 

Czy to możliwe?

Odpowiedz

11

Gotowe rozwiązanie dla tego rodzaju akumulacji pojedynczego przejścia realizowane jest przez Boost.Accumulators. Tworzysz pojedynczy akumulator, powiedzmy o sumie, liczbie i średniej, wypełnij go, a następnie wyodrębnij wszystkie trzy wyniki na końcu.

9

Nie można połączyć dwóch różnych algorytmów do przeplotu. Algorytmy kontrolują przepływ, a Ty możesz mieć tylko jeden przepływ. Teraz, w danym przypadku można zasymulować:

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

Jest to całkowita hack, ale coś takiego:

#include <iostream> 
#include <algorithm> 
#include <tuple> 
#include <iterator> 
#include <sstream> 

namespace Custom { 
    template <class InputIterator, class T, class Bind, typename... Args> 
     std::tuple<Args...> accumulate (InputIterator first, InputIterator last, 
      T init, T& output, Bind bind, Args&... args) 
    { 
     while (first!=last) { 
     init = bind(init, *first, args...); 
     ++first; 
     } 
     output = init; 
     std::tuple<Args...> tuple(args...); 
     return tuple; 
    } 
} 

int main() { 
    int total = 0, count = 0; 
    std::istringstream is; 
    is.str("1 2 3 4 5"); 
    std::tie(count) = Custom::accumulate(std::istream_iterator<int>(is), 
     std::istream_iterator<int>(), 
     0, 
     total, 
     std::bind([&] (int a, int b, int& count) { ++count; return a + b; }, 
     std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 
     count); 
    std::cout << total << " " << count; 
    return 0; 
} 
Powiązane problemy