¿Cuáles son las buenas maneras de encontrar la suma de todos los elementos en a std::vector
?
Supongamos que tengo un vector std::vector<int> vector
con algunos elementos. Ahora quiero encontrar la suma de todos los elementos. ¿Cuáles son las diferentes formas de lo mismo?
std::accumulate
en Boost? (Si es así, ¿por qué?) ¿Está buscando funciones que hagan algo similarstd::accumulate
? (Si es así, ¿qué?)std::accumulate
, presumiblemente también quiere que sea diferente en algún aspecto (de lo contrario, podría usarlostd::accumulate
); ¿Qué diferencia (s)std::accumulate
estás buscando?Respuestas:
En realidad, hay bastantes métodos.
C ++ 03
Clásico para loop:
Usando un algoritmo estándar:
Nota importante: El tipo del último argumento se usa no solo para el valor inicial, sino también para el tipo del resultado . Si coloca un int allí, acumulará entradas incluso si el vector tiene flotación. Si está sumando números de coma flotante, cambie
0
a0.0
o0.0f
(gracias a nneonneo). Vea también la solución C ++ 11 a continuación.C ++ 11 y superior
si. Seguimiento automático del tipo de vector incluso en caso de cambios futuros:
Utilizando
std::for_each
:Uso de un bucle for basado en rango (gracias a Roger Pate):
fuente
std::for_each
con un functor, solo se necesitan más líneas de código para definir que el lambda C ++ 0x.for_each
?accumulate
sería más conciso (incluso si no necesita la lambda)accumulate
dentro,for_each
pero este ejemplo no es útil (con fines de aprendizaje), ya que muestra que también podemos tener lambdas anidadas :-)accumulate
. El último tipo de argumento se usa no solo para el valor inicial, sino también para el tipo del resultado. Si pones unint
allí, se acumularáint
s incluso si el vector tienefloat
. El resultado puede ser sutilmente incorrecto, y el compilador volverá a generar el resultado en un flotante sin decírselo.for_each
si tienesaccumulate
?La forma más fácil es usar
std:accumuate
unvector<int> A
:fuente
Prasoon ya ha ofrecido una gran cantidad de formas diferentes (y buenas) de hacer esto, ninguna de las cuales necesita repetirse aquí. Sin embargo, me gustaría sugerir un enfoque alternativo para la velocidad.
Si va a hacer esto un poco, es posible que desee considerar "subclasificar" su vector para que una suma de elementos se mantenga por separado (en realidad no es un subclasificación de vectores que es dudoso debido a la falta de un destructor virtual: estoy hablando más de una clase que contiene la suma y un vector dentro de ella, en
has-a
lugar deis-a
, y proporciona los métodos de tipo vector).Para un vector vacío, la suma se establece en cero. En cada inserción en el vector, agregue el elemento que se inserta a la suma. En cada eliminación, restarlo. Básicamente, cualquier cosa que pueda cambiar el vector subyacente se intercepta para garantizar que la suma se mantenga constante.
De esa manera, tiene un método O (1) muy eficiente para "calcular" la suma en cualquier momento (solo devuelva la suma calculada actualmente). La inserción y la eliminación tardarán un poco más a medida que ajuste el total y debe tener en cuenta este éxito de rendimiento.
Los vectores en los que la suma se necesita con más frecuencia que el vector que se cambia son los que probablemente se beneficiarán de este esquema, ya que el costo de calcular la suma se amortiza en todos los accesos. Obviamente, si solo necesita la suma cada hora y el vector cambia tres mil veces por segundo, no será adecuado.
Algo como esto sería suficiente:
Obviamente, ese es un seudocódigo y es posible que desee tener un poco más de funcionalidad, pero muestra el concepto básico.
fuente
std::vector
que no está destinado a subclasificar.has-a
vector dentro de ella, en lugar de ser una subclase adecuada (is-a
).operator[](int)
, los iteradores no constantes ...¿Por qué realizar la suma hacia adelante cuando puedes hacerlo al revés ? Dado:
Podemos usar suscripciones, contando hacia atrás:
Podemos usar "suscripciones" controladas por rango, contando hacia atrás (por si acaso)
Podemos usar iteradores inversos en un ciclo for:
Podemos usar iteradores hacia adelante, iterando hacia atrás, en un bucle for (¡oooh, complicado!):
Podemos usar
accumulate
con iteradores inversos:Podemos usar
for_each
con una expresión lambda usando iteradores inversos:Por lo tanto, como puede ver, hay tantas formas de sumar el vector hacia atrás como de sumar el vector hacia adelante, y algunas de ellas son mucho más emocionantes y ofrecen muchas más oportunidades para errores fuera de uno.
fuente
v.size()
.fuente
boost::accumulate
es solo una envolturastd::accumulate
.#include <numeric>
ystd::accumulate(v.begin(), v.end(), (int64_t)0);
. Observe que el tipo del valor del acumulador inicial se usa como el tipo de acumulador, por lo que si desea sumar elementos de 8 bits en un resultado de 64 bits, así es como lo hace.También se puede usar
std::valarray<T>
asíAlgunos pueden no encontrar esta manera eficiente ya que el tamaño de las
valarray
necesidades debe ser tan grande como el tamaño del vector y la inicializaciónvalarray
también llevará tiempo.En ese caso, no lo use y tómelo como otra forma de resumir la secuencia.
fuente
Solo C ++ 0x:
Esto es similar al BOOST_FOREACH mencionado en otra parte y tiene el mismo beneficio de claridad en situaciones más complejas, en comparación con los functores con estado utilizados con acumular o para cada uno.
fuente
for (int n : v) sum += n;
afor (auto n : v) sum += n;
él, funcionará con cualquier plantilla de vector. Sabía que OP se refiere al vector <int>, pero de esta manera es un poco más general :-)Soy un usuario de Perl, un juego que tenemos es encontrar diferentes formas de incrementar una variable ... eso no es realmente diferente aquí. La respuesta a cuántas formas de encontrar la suma de los elementos de un vector en C ++ es probablemente
an infinity
...Mis 2 centavos:
Usando BOOST_FOREACH, para liberarse de la sintaxis del iterador feo:
iterando sobre índices (realmente fácil de leer).
Este otro es destructivo, accediendo al vector como una pila:
fuente
start + length
). Los iteradores reales también deberían optimizarse por completo. Recuerda, no es perl; está completamente compilado a asm, no interpretado.fuente
int
para indexar astd::vector
no es seguro en general.v.size()
puede ser mayor que el valor más alto que se puede almacenarint
(tenga en cuenta que con algunas plataformas y compiladores de destinosize_of(int) < size_of(size_t)
). En este caso, su código desbordará el índice. Se debe preferir std :: vector <T> :: size_type .Es fácil. C ++ 11 proporciona una manera fácil de resumir elementos de un vector.
fuente