Quais são as boas maneiras de encontrar a soma de todos os elementos em a std::vector
?
Suponha que eu tenha um vetor std::vector<int> vector
com alguns elementos. Agora eu quero encontrar a soma de todos os elementos. Quais são as diferentes maneiras para o mesmo?
std::accumulate
no Boost? (Se sim, por quê?) Você está procurando funções que façam algo semelhantestd::accumulate
? (Se sim, qual?)std::accumulate
, presumivelmente também deseja que seja diferente em algum aspecto (caso contrário, você pode simplesmente usarstd::accumulate
); que diferença (s)std::accumulate
você está procurando?Respostas:
Na verdade, existem alguns métodos.
C ++ 03
Clássico para loop:
Usando um algoritmo padrão:
Nota importante: O tipo do último argumento é usado não apenas para o valor inicial, mas também para o tipo do resultado . Se você colocar um int lá, ele acumulará ints, mesmo que o vetor tenha flutuado. Se você estiver somando números de ponto flutuante, altere
0
para0.0
ou0.0f
(graças a nneonneo). Veja também a solução C ++ 11 abaixo.C ++ 11 e superior
b. Acompanhar automaticamente o tipo de vetor, mesmo em caso de alterações futuras:
Usando
std::for_each
:Usando um loop for baseado em intervalo (graças a Roger Pate):
fonte
std::for_each
com um functor, basta levar mais linhas de código para definir do que o lambda C ++ 0x.for_each
?accumulate
seria mais conciso (mesmo que não precisa do lambda)accumulate
dentrofor_each
, mas não é este exemplo útil (para a aprendizagem de propósito), pois mostra que também pode ter lambdas aninhados :-)accumulate
. O tipo do último argumento é usado não apenas para o valor inicial, mas para o tipo do resultado. Se você colocar umint
lá, ele acumularáint
s, mesmo que o vetor tenhafloat
. O resultado pode estar sutilmente errado, e o compilador converterá o resultado em um float sem avisar.for_each
se tiveraccumulate
?A maneira mais fácil é usar
std:accumuate
umvector<int> A
:fonte
Prasoon já ofereceu várias maneiras diferentes (e boas) de fazer isso, nenhuma das quais precisa ser repetida aqui. Eu gostaria de sugerir uma abordagem alternativa para a velocidade, no entanto.
Se você estiver fazendo isso um pouco, considere "subclassificar" seu vetor para que uma soma de elementos seja mantida separadamente ( na verdade, não um vetor de subclasse que é duvidoso devido à falta de um destruidor virtual - estou falando mais de uma classe que contém a soma e um vetor dentro dela,
has-a
e nãois-a
e fornece os métodos semelhantes a vetores).Para um vetor vazio, a soma é definida como zero. Em todas as inserções no vetor, adicione o elemento que está sendo inserido na soma. Em cada exclusão, subtraia-o. Basicamente, qualquer coisa que possa alterar o vetor subjacente é interceptada para garantir que a soma seja mantida consistente.
Dessa forma, você tem um método O (1) muito eficiente para "calcular" a soma a qualquer momento (basta retornar a soma calculada atualmente). A inserção e exclusão levarão um pouco mais de tempo enquanto você ajusta o total e você deve levar em consideração esse desempenho atingido.
Os vetores em que a soma é necessária com mais frequência do que o vetor é alterado são os que mais se beneficiam com esse esquema, uma vez que o custo do cálculo da soma é amortizado em todos os acessos. Obviamente, se você precisar da soma a cada hora e o vetor mudar três mil vezes por segundo, isso não será adequado.
Algo assim seria suficiente:
Obviamente, isso é pseudo-código e você pode querer ter um pouco mais de funcionalidade, mas mostra o conceito básico.
fonte
std::vector
não se destina a subclasses.has-a
vetor dentro dela, em vez de ser uma subclasse adequada (is-a
).operator[](int)
, iterators não-const ...Por que executar a soma para a frente quando você pode fazer isso para trás ? Dado:
Podemos usar a assinatura, contando ao contrário:
Podemos usar a "assinatura" com intervalo verificado, contando para trás (apenas no caso):
Podemos usar iteradores reversos em um loop for:
Podemos usar iteradores para frente, iterando para trás, em um loop for (oooh, complicado!):
Podemos usar
accumulate
com iteradores reversos:Podemos usar
for_each
com uma expressão lambda usando iteradores reversos:Portanto, como você pode ver, existem tantas maneiras de somar o vetor para trás quanto de somar o vetor para frente, e algumas delas são muito mais empolgantes e oferecem uma oportunidade muito maior para erros isolados.
fonte
v.size()
.fonte
boost::accumulate
é apenas um invólucrostd::accumulate
.#include <numeric>
estd::accumulate(v.begin(), v.end(), (int64_t)0);
. Observe que o tipo do valor inicial do acumulador é usado como o tipo de acumulador; portanto, se você deseja somar elementos de 8 bits em um resultado de 64 bits, é assim que você faz.Pode-se também usar
std::valarray<T>
assimAlguns podem não achar esse caminho eficiente, pois o tamanho das
valarray
necessidades precisa ser tão grande quanto o tamanho do vetor e a inicializaçãovalarray
também levará tempo.Nesse caso, não o use e tome-o como mais uma maneira de resumir a sequência.
fonte
Apenas C ++ 0x:
Isso é semelhante ao BOOST_FOREACH mencionado em outro lugar e tem o mesmo benefício de clareza em situações mais complexas, em comparação com os funcores com estado usados com acumular ou for_each.
fonte
for (int n : v) sum += n;
parafor (auto n : v) sum += n;
ele, funcionará com qualquer modelo de vetor. I conhecida referes op para vector <int>, mas desta forma é ligeiramente mais geral :-)Eu sou um usuário Perl, um jogo que temos é encontrar todas as maneiras diferentes de incrementar uma variável ... isso não é realmente diferente aqui. A resposta para quantas maneiras de encontrar a soma dos elementos de um vetor em C ++ é provavelmente
an infinity
...Meus 2 centavos:
Usando BOOST_FOREACH, para se livrar da sintaxe feia do iterador:
iterando nos índices (realmente fáceis de ler).
Este outro é destrutivo, acessando o vetor como uma pilha:
fonte
start + length
). Os iteradores reais também devem otimizar completamente. Lembre-se, não é perl; é totalmente compilado para asm, não interpretado.fonte
int
para indexar astd::vector
não é seguro em geral.v.size()
pode ser maior que o valor mais alto que pode ser armazenadoint
(observe que em algumas plataformas e compiladores de destinosize_of(int) < size_of(size_t)
). Nesse caso, seu código irá estourar o índice. std :: vector <T> :: size_type deve ser preferido.Isso é fácil. O C ++ 11 fornece uma maneira fácil de resumir elementos de um vetor.
fonte