c++ - libreria - Ejecute dos<algorithm> s uno al lado del otro en el mismo rango de iterador de entrada
que es un iterador en java (3)
Si quiero calcular la suma de un grupo de números recuperados de un std::istream
, puedo hacer lo siguiente:
// std::istream & is = ...
int total = std::accumulate(std::istream_iterator<int>(is),
std::istream_iterator<int>(),
0);
Sin embargo, si quiero calcular su promedio, necesito acumular dos resultados diferentes:
- la suma total (
std::accumulate
) - el conteo total (
std::distance
)
¿Hay alguna manera de "fusionar" estos dos algoritmos y ejecutarlos "uno al lado del otro" en una sola pasada de un rango de iterador? Me gustaría hacer algo como:
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;
es posible?
Esto es un truco total, pero algo como esto:
#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;
}
No puede fusionar dos algoritmos diferentes para intercalar. Los algoritmos controlan el flujo, y solo puedes tener un flujo. Ahora, en tu caso particular, puedes simularlo:
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; });
Una solución preparada para este tipo de acumulación de un solo paso es implementada por Boost.Accumulators . Usted crea un único acumulador, digamos para sumar, contar y promediar, llenarlo y luego extraer los tres resultados al final.