2008-11-24 11 views
30

Je suis un programmeur C/Python en terre C++ fonctionnant avec la STL pour la première fois.C++ étendre un vecteur avec un autre vecteur

En Python, l'extension d'une liste avec une autre liste utilise la méthode .extend:

>>> v = [1, 2, 3] 
>>> v_prime = [4, 5, 6] 
>>> v.extend(v_prime) 
>>> print(v) 
[1, 2, 3, 4, 5, 6] 

J'utilise actuellement cette approche algorithmique pour étendre les vecteurs en C++:

v.resize(v.size() + v_prime.size()); 
copy(v_prime.begin(), v_prime.end(), v.rbegin()); 

Est-ce la façon canonique étendre les vecteurs, ou s'il y a un moyen plus simple que je manque?

+0

double possible de [Concaténer deux std :: vecteurs] (http://stackoverflow.com/questions/201718/concatenating-two-stdvectors) –

Répondre

45

De here

// reserve() is optional - just to improve performance 
v.reserve(v.size() + distance(v_prime.begin(),v_prime.end())); 
v.insert(v.end(),v_prime.begin(),v_prime.end()); 
+0

Je ne pense pas qu'il y ait une spécialisation de vector :: insert pour les itérateurs d'entrée à accès aléatoire, donc si les performances sont importantes, réservez d'abord(). –

+9

VC++ 9.0 et GCC 4.3.2 déterminent la catégorie d'itérateur en interne, donc vous n'avez pas besoin de réserver. –

+12

Je sais que c'est 8 ans, mais y a-t-il une raison pour laquelle vous avez utilisé 'distance()' au lieu de simplement 'v_prime.size()'? – Holt

18
copy(v_prime.begin(), v_prime.end(), back_inserter(v)); 
+0

Je pense que l'espace doit encore être reserve() - d pour améliorer les performances –

+1

+1, puisque l'interrogateur a demandé "le plus simple", pas "le plus rapide", donc réserver de l'espace (inutile de le mentionner). –

+0

Je pense que la solution dmitry est à la fois plus simple et plus rapide. upvote pour ce gars-là :) –

1

me fallait deux variantes différentes de la fonction extend en C++ 14, où une sémantique de déplacement pris en charge pour chaque élément du vecteur pour être joints.

vec est votre v et ext est v_prime.

/** 
* Extend a vector with elements, without destroying source one. 
*/ 
template<typename T> 
void vector_extend(std::vector<T> &vec, const std::vector<T> &ext) { 
    vec.reserve(vec.size() + ext.size()); 
    vec.insert(std::end(vec), std::begin(ext), std::end(ext)); 
} 

/** 
* Extend a vector with elements with move semantics. 
*/ 
template<typename T> 
void vector_extend(std::vector<T> &vec, std::vector<T> &&ext) { 
    if (vec.empty()) { 
     vec = std::move(ext); 
    } 
    else { 
     vec.reserve(vec.size() + ext.size()); 
     std::move(std::begin(ext), std::end(ext), std::back_inserter(vec)); 
     ext.clear(); 
    } 
} 
3

Il existe plusieurs façons d'atteindre votre cible.

std :: vector :: insérer

Le vecteur peut être étendu par l'insertion de nouveaux éléments avant de l'élément à la position spécifiée, en augmentant efficacement la taille du conteneur par le nombre d'éléments insérés. Vous pouvez suivre l'une des approches ci-dessous. La deuxième version utilise C++ 11 et peut être considérée comme une réponse plus générique, car b peut aussi être un tableau. Parfois, il est recommandé d'utiliser la fonction de réserve avant d'utiliser std :: vector :: insert. La fonction std :: vector :: reserve augmente la capacité du conteneur à une valeur supérieure ou égale à new_cap. Si new_cap est supérieur à la capacité actuelle(), un nouveau stockage est alloué, sinon la méthode ne fait rien.

a.reserve(a.size() + distance(b.begin(), b.end())); 

L'utilisation de la fonction de réserve n'est pas requise mais peut être recommandée. Et il est préférable d'utiliser la réserve si vous insérez plusieurs fois dans un vecteur dont vous connaissez la taille finale, et que cette taille est importante. Sinon, il est préférable de laisser le STL développer votre vecteur au besoin.

std :: copie

std :: copie est la deuxième option que vous pouvez envisager pour atteindre votre cible. Cette fonction copie les éléments de la plage (premier, dernier) dans la plage commençant au résultat.

std::copy (b.begin(), b.end(), std::back_inserter(a)); 

Toutefois, l'utilisation de std :: copie est plus lent que l'utilisation de std :: vector :: insert(), parce que std :: copy() ne peut pas réserver assez d'espace avant la main (il ne avoir accès au vecteur lui-même, seulement à un itérateur qui a), alors que std :: vector :: insert(), étant une fonction membre, peut. En raison de cela, std :: copy est en effet plus lent que l'utilisation de std :: vector :: insert. La plupart des gens utilisent STD :: copy sans connaître ce scénario.

boost :: push_back

La troisième option que vous pouvez envisager est l'utilisation de la fonction push_back de boost.

boost::push_back(a, b); 
1

en utilisant std::vector::insert;

A.reserve(A.size() + B.size()); 
A.insert(A.end(), B.begin(), B.end()); 

reserve() est facultative, mais elle contribue à améliorer les performances.


générateur de code Convienent pour gagner de précieuses secondes:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script><script src="https://cdn.jsdelivr.net/clipboard.js/1.6.0/clipboard.min.js"></script><script>function generateCode(){codeTemplate="{0}.reserve({0}.size() + {1}.size()); \n{0}.insert({0}.end(), {1}.begin(), {1}.end());",first=document.getElementById("1").value,second=document.getElementById("2").value,""==first&&(first="A"),""==second&&(second="B"),document.getElementById("c").innerHTML=String.format(codeTemplate,first,second)}String.format||(String.format=function(a){var b=Array.prototype.slice.call(arguments,1);return a.replace(/{(\d+)}/g,function(a,c){return"undefined"!=typeof b[c]?b[c]:a})});</script><div class="A" style="margin:3% 10% 1% 10%;"><label for="1">First vector name:</label><input id="1"/><br/><label for="1">Second vector name:</label><input id="2"/><div class="D"><a class="waves-effect waves-light btn red col" onclick="generateCode();" style="margin:0 0 4% 0;">Generate Code</a></div><textarea id="c" onclick="this.select()" style="border:none;height:auto;overflow: hidden;font-family:Consolas,Monaco;">A.reserve(A.size() + B.size());&#13;&#10;A.insert(A.end(), B.begin(), B.end());</textarea></div>

Questions connexes