web-dev-qa-db-fra.com

Comment ajouter élément par élément de deux vecteurs STL?

La question est assez stupide, mais je dois le faire de manière très efficace - cela sera refait dans mon code. J'ai une fonction qui renvoie un vecteur et je dois ajouter les valeurs renvoyées à un autre vecteur, élément par élément. Assez facile:

vector<double> result;
vector<double> result_temp
for(int i=0; i< 10; i++) result_temp.Push_back(i);

result += result_temp //I would like to do something like that.
for(int i =0; i< result_temp.size();i++)result[i] += result_temp[i]; //this give me segfault

L'opération mathématique que j'essaie de faire est

u [i] = u [i] + v [i] pour tout i

Ce qui peut être fait?

Merci

EDIT: ajout d'une simple initialisation, ce n'est pas le but. Comment le résultat devrait-il être initialisé?

22
Ivan

Si vous essayez d’ajouter une vector à une autre, vous pouvez utiliser quelque chose comme ce qui suit. Celles-ci proviennent de l'une de mes bibliothèques d'utilitaires - deux surcharges operator+= pour std::vector: l'une ajoute un seul élément à la vector, l'autre ajoute une vector entière:

template <typename T>
std::vector<T>& operator+=(std::vector<T>& a, const std::vector<T>& b)
{
    a.insert(a.end(), b.begin(), b.end());
    return a;
}

template <typename T>
std::vector<T>& operator+=(std::vector<T>& aVector, const T& aObject)
{
    aVector.Push_back(aObject);
    return aVector;
}

Si vous essayez d'effectuer une somme (c'est-à-dire, créez une nouvelle vector contenant les sommes des éléments de deux autres vectors), vous pouvez utiliser quelque chose comme ce qui suit:

#include <algorithm>
#include <functional>

template <typename T>
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b)
{
    assert(a.size() == b.size());

    std::vector<T> result;
    result.reserve(a.size());

    std::transform(a.begin(), a.end(), b.begin(), 
                   std::back_inserter(result), std::plus<T>());
    return result;
}

De même, vous pouvez implémenter une surcharge operator+=.

30
James McNellis

Il semble bien que le problème soit d'accéder aux valeurs de result qui n'existent pas. tzaman montre comment initialiser le résultat sur 10 éléments, chacun avec la valeur 0.

Vous devez maintenant appeler la fonction transform (à partir de <algorithm>), en appliquant l'objet de fonction plus (à partir de <fonctionnel>):

std::transform(result.begin(), result.end(), result_temp.begin(),
               result.begin(), std::plus<double>());

Cela effectue une itération sur result et result_temp, applique plus qui ajoute des doublons et écrit la somme sur result.

30
Jon Reid

Un exemple concret de la réponse de Jon Reid:

std::array<double,3> a = {1, 2, 3};
std::array<double,3> b = {4, 5, 6};
std::transform(a.begin( ), a.end( ), b.begin( ), a.begin( ),std::plus<double>( ));
ASSERT_TRUE(a[0] == 5);
ASSERT_TRUE(a[1] == 7);
ASSERT_TRUE(a[2] == 9);
8
gerardw

Vous devez d'abord initialiser result à tous les zéros; le simple fait de déclarer la variable n'alloue aucun élément. 

Essaye ça:

vector<double> result(10); // default-initialize to 10 elements
vector<double> result_temp;
for(int i=0; i< 10; i++) 
    result_temp.Push_back(i);

for(int i =0; i< result_temp.size();i++)
    result[i] += result_temp[i];
1
tzaman

Si votre code est segmenté, alors c'est un problème de correction, pas d'efficacité.

Pour réaliser "u [i] = u [i] + v [i] pour tout i", je ferais en gros ce que vous avez fait:

assert(u.size() == v.size()); // will fail with your initialization code, since
                              // your "result" has size 0, not size 10.
                              // perhaps do u.resize(v.size());
for (size_t i = 0; i < u.size(); ++i) {
    u[i] += v[i];
}

Si vous vous souciez vraiment des performances de votre programme (c’est-à-dire que vous avez écrit une version de base et qu’il est tellement lent que votre programme ne répond pas aux exigences, et vous avez prouvé que c’est le code qui prend le plus de temps) , alors vous pourriez essayer:

  • activer beaucoup d'optimisation dans votre compilateur (en fait, je le fais habituellement par défaut même en l'absence de problème de performances),
  • utiliser des itérateurs au lieu d'index (fait rarement une grande différence, mais il est assez facile de comparer les deux),
  • dérouler la boucle un peu (peut faire une différence de vitesse intéressante, mais c'est assez sensible au cas particulier, et cela encourage les erreurs de codage).
  • en regardant les instructions SIMD spécifiques à la plate-forme plutôt que C++. Ensuite, utilisez les composants intrinsèques de l'assembleur ou du compilateur intégré pour ces instructions.

Néanmoins, vous n'avez pas à vous soucier des performances avant que votre code soit correct ;-). "Faites que ça marche, que vous fassiez bien, que vous fassiez vite" est une devise raisonnable, même si souvent vous n'avez pas besoin d'aller jusqu'à l'étape 3.

std::valarray a en fait exactement le operator+= que vous voulez. Avant de remplacer tous vos vecteurs par valarrays, sachez que cela ne signifie pas forcément que c'est "plus efficace" qu'une simple boucle - je ne sais pas à quel point les réalisateurs prennent valarray au sérieux. Vous pouvez toujours regarder la source dans votre implémentation. Je ne sais pas non plus pourquoi la fonctionnalité arithmétique à données multiples de valarray n'a pas été définie dans le cadre de vector, mais il y a généralement une raison.

1
Steve Jessop

Je suis avec @James McNellis - ce code semble correct, tant que result et result_temp ont la même longueur.

Aussi - pourquoi avez-vous déclaré result, mais utilisé la variable result_v - est-ce ainsi que le code est réellement écrit? Si oui, c'est un problème

0
Dave McClelland

Le code semble correct, mais ma première tendance serait de modifier le code qui remplit le vecteur avec des valeurs à ajouter aux valeurs du premier vecteur afin de prendre en référence le premier vecteur et d’y ajouter directement plutôt que de créer un nouveau vecteur. qui est retourné. C'est juste inefficace.

Si vous ne pouvez pas modifier la fonction de cette manière, vous pouvez peut-être la modifier afin qu’elle prenne une référence à un vecteur qu’elle efface, puis insère les valeurs dans afin de ne pas copier les vecteurs. Cela peut devenir coûteux si vous le faites beaucoup.

Si vous essayez d’obtenir cela aussi rapidement que possible, vous devriez utiliser le pré-incrémentation avec des itérateurs plutôt que le post-incrémentation. Le temporaire créé par la post-incrémentation ne peut pas être optimisé sans traitement lorsqu'il s'agit d'opérateurs surchargés plutôt que de types intégrés. Ainsi, vous continuez à créer et à détruire temporairement chaque itération de votre boucle. EDIT: Comme cela a été souligné dans les commentaires, vous utilisez des indices ici plutôt que des itérateurs (je ne prêtais évidemment pas assez d'attention), ce conseil ne s'applique donc pas vraiment ici. Cependant, dans le cas où vous utilisez des itérateurs, il est toujours valide.

En dehors de cela, si vous essayez d'ajouter tous les éléments de deux vecteurs, ce que vous avez est probablement la solution la plus efficace possible. Il existe de meilleurs moyens si vous souhaitez insérer les éléments d’un vecteur dans un autre, mais si vous n’ajoutez que leurs valeurs, ce que vous avez l’a bel aspect. Je m'attendrais à ce que l'utilisation d'algorithmes STL soit au mieux aussi rapide et probablement plus lente en raison d'appels de fonction supplémentaires, mais vous devrez probablement le profiler pour en être sûr.

0
Jonathan M Davis