¿Cómo resumir elementos de un vector de C++?

Resuelto Prasoon Saurav asked hace 14 años • 13 respuestas

¿ Cuáles son las buenas formas de encontrar la suma de todos los elementos en a std::vector?

Supongamos que tengo un vector std::vector<int> vectorcon algunos elementos. Ahora quiero encontrar la suma de todos los elementos. ¿Cuáles son las diferentes formas de lograr lo mismo?

Prasoon Saurav avatar Jul 11 '10 10:07 Prasoon Saurav
Aceptado

En realidad existen bastantes métodos.

int sum_of_elems = 0;

C++03

  1. Clásico para bucle:

     for(std::vector<int>::iterator it = vector.begin(); it != vector.end(); ++it)
         sum_of_elems += *it;
    
  2. Usando un algoritmo estándar:

     #include <numeric>
    
     sum_of_elems = std::accumulate(vector.begin(), vector.end(), 0);
    

    Nota importante: el tipo del último argumento se utiliza no sólo para el valor inicial, sino también para el tipo del resultado . Si coloca un int allí, acumulará int incluso si el vector tiene flotación. Si está sumando números de punto flotante, cambie 0a 0.0o 0.0f( gracias a nneonneo ). Consulte también la solución C++11 a continuación.

C++11 y superior

  1. b. Realizar un seguimiento automático del tipo de vector incluso en caso de cambios futuros:

     #include <numeric>
    
     sum_of_elems = std::accumulate(vector.begin(), vector.end(),
                                    decltype(vector)::value_type(0));
    
  2. Usando std::for_each:

     std::for_each(vector.begin(), vector.end(), [&] (int n) {
         sum_of_elems += n;
     });
    
  3. Usando un bucle for basado en rango ( gracias a Roger Pate ):

     for (auto& n : vector)
         sum_of_elems += n;
    

C ++ 17 y superior

  1. El uso std::reducede which también se ocupa del tipo de resultado, por ejemplo, si tiene std::vector<int>, obtendrá intel resultado. Si lo tienes std::vector<float>, obtienes float. O si lo tiene std::vector<std::string>, obtiene std::string(todas las cadenas concatenadas). Interesante, ¿no?

    auto result = std::reduce(v.begin(), v.end());
    

    Hay otras sobrecargas de esta función que puedes ejecutar incluso en paralelo, en caso de que tengas una colección grande y quieras obtener el resultado rápidamente.

Prasoon Saurav avatar Jul 11 '2010 04:07 Prasoon Saurav

La forma más sencilla es utilizar std:accumulateun vector<int> A:

#include <numeric>
cout << accumulate(A.begin(), A.end(), 0);
beahacker avatar Oct 07 '2018 04:10 beahacker

Prasoon ya ha ofrecido una serie 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 con bastante frecuencia, es posible que desee considerar "subclasificar" su vector para que una suma de elementos se mantenga por separado (en realidad no subclasificar el vector, lo cual 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, has-aen lugar de is-ay proporciona métodos similares a vectores).

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, réstalo. Básicamente, cualquier cosa que pueda cambiar el vector subyacente se intercepta para garantizar que la suma se mantenga constante.

De esa manera, tendrá un método O(1) muy eficiente para "calcular" la suma en cualquier momento (simplemente devuelva la suma calculada actualmente). La inserción y eliminación tardarán un poco más a medida que ajuste el total y debe tener en cuenta este impacto en el rendimiento.

Los vectores en los que se necesita la suma con más frecuencia de la que se cambia el vector 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 necesitas la suma cada hora y el vector cambia tres mil veces por segundo, no será adecuado.

Algo como esto sería suficiente:

class UberVector:
    private Vector<int> vec
    private int sum

    public UberVector():
        vec = new Vector<int>()
        sum = 0

    public getSum():
        return sum

    public add (int val):
        rc = vec.add (val)
        if rc == OK:
            sum = sum + val
        return rc

    public delindex (int idx):
        val = 0
        if idx >= 0 and idx < vec.size:
            val = vec[idx]
        rc =  vec.delindex (idx)
        if rc == OK:
            sum = sum - val
        return rc

Obviamente, eso es pseudocódigo y es posible que desees tener un poco más de funcionalidad, pero muestra el concepto básico.

paxdiablo avatar Jul 11 '2010 04:07 paxdiablo

¿Por qué realizar la suma hacia adelante cuando puedes hacerlo hacia atrás ? Dado:

std::vector<int> v;     // vector to be summed
int sum_of_elements(0); // result of the summation

Podemos usar subíndices, contando hacia atrás:

for (int i(v.size()); i > 0; --i)
    sum_of_elements += v[i-1];

Podemos utilizar "subíndices" de rango comprobado, contando hacia atrás (por si acaso):

for (int i(v.size()); i > 0; --i)
    sum_of_elements += v.at(i-1);

Podemos usar iteradores inversos en un bucle for:

for(std::vector<int>::const_reverse_iterator i(v.rbegin()); i != v.rend(); ++i)
    sum_of_elements += *i;

Podemos usar iteradores hacia adelante, iterando hacia atrás, en un bucle for (¡oooh, complicado!):

for(std::vector<int>::const_iterator i(v.end()); i != v.begin(); --i)
    sum_of_elements += *(i - 1);

Podemos usar accumulatecon iteradores inversos:

sum_of_elems = std::accumulate(v.rbegin(), v.rend(), 0);

Podemos usar for_eachuna expresión lambda usando iteradores inversos:

std::for_each(v.rbegin(), v.rend(), [&](int n) { sum_of_elements += n; });

Entonces, 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 interesantes y ofrecen muchas más oportunidades de cometer errores uno por uno.

James McNellis avatar Jul 11 '2010 04:07 James McNellis
#include<boost/range/numeric.hpp>
int sum = boost::accumulate(vector, 0);
rafak avatar Aug 06 '2010 15:08 rafak