J'utilise la multipression et je souhaite fusionner les résultats. Par exemple:
std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
Je veux que AB ait le contenu de A et le contenu de B dans cet ordre. Quel est le moyen le plus efficace de faire quelque chose comme ça?
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
C’est précisément ce à quoi sert la fonction membre std::vector::insert
std::vector<int> AB = A;
AB.insert(AB.end(), B.begin(), B.end());
Cela dépend si vous avez vraiment besoin de concaténer physiquement les deux vecteurs ou si vous voulez donner l’apparence d’une concaténation dans l’intérêt de l’itération. Le boost :: rejoindre la fonction
http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/utilities/join.html
vais vous donner ceci.
std::vector<int> v0;
v0.Push_back(1);
v0.Push_back(2);
v0.Push_back(3);
std::vector<int> v1;
v1.Push_back(4);
v1.Push_back(5);
v1.Push_back(6);
...
BOOST_FOREACH(const int & i, boost::join(v0, v1)){
cout << i << endl;
}
devrait vous donner
1
2
3
4
5
6
Note boost :: join ne copie pas les deux vecteurs dans un nouveau conteneur, mais génère une paire d'itérateurs (plage) couvrant l'étendue des deux conteneurs. Il y aura une surcharge de performances mais peut-être moins que de copier toutes les données dans un nouveau conteneur en premier.
Basé sur Kiril V. Lyadvinsky answer , j'ai créé une nouvelle version. Cet extrait utilise un modèle et une surcharge. Avec cela, vous pouvez écrire vector3 = vector1 + vector2
et vector4 += vector3
. J'espère que ça peut aider.
template <typename T>
std::vector<T> operator+(const std::vector<T> &A, const std::vector<T> &B)
{
std::vector<T> AB;
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() ); // add A;
AB.insert( AB.end(), B.begin(), B.end() ); // add B;
return AB;
}
template <typename T>
std::vector<T> &operator+=(std::vector<T> &A, const std::vector<T> &B)
{
A.reserve( A.size() + B.size() ); // preallocate memory without erase original data
A.insert( A.end(), B.begin(), B.end() ); // add B;
return A; // here A could be named AB
}
Encore une variante simple qui n’a pas encore été mentionnée:
copy(A.begin(),A.end(),std::back_inserter(AB));
copy(B.begin(),B.end(),std::back_inserter(AB));
Et en utilisant l'algorithme de fusion:
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
#include <sstream>
#include <string>
template<template<typename, typename...> class Container, class T>
std::string toString(const Container<T>& v)
{
std::stringstream ss;
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(ss, ""));
return ss.str();
};
int main()
{
std::vector<int> A(10);
std::vector<int> B(5); //zero filled
std::vector<int> AB(15);
std::for_each(A.begin(), A.end(),
[](int& f)->void
{
f = Rand() % 100;
});
std::cout << "before merge: " << toString(A) << "\n";
std::cout << "before merge: " << toString(B) << "\n";
merge(B.begin(),B.end(), begin(A), end(A), AB.begin(), [](int&,int&)->bool {});
std::cout << "after merge: " << toString(AB) << "\n";
return 1;
}
Dans le sens de la réponse de Bradgonesurfing, il arrive souvent que l'on ne oblige) pas = (obligatoirement concaténer deux vecteurs, mais simplement travailler avec eux comme s'ils étaient concaténés. Cela semble être votre cas et vous pouvez le faire sans utiliser les bibliothèques Boost.
L'astuce consiste à créer un proxy vectoriel: une classe wrapper manipulant références pour les deux vecteurs, vus de l'extérieur comme un seul, contigus, qui peuvent ensuite être consultés/parcourus exactement comme vous le feriez sur un réel. vecteur.
USAGE
std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B); // ----> O(1)
for (size_t i = 0; i < AB.size(); i++)
std::cout << AB[i] << " "; // ----> Output: 1 2 3 4 5 10 20 30
std::cout << AB[6]; // ----> Output: 20
IMPLÉMENTATION
template <class T>
class VecProxy {
private:
std::vector<T>& v1;
std::vector<T>& v2;
public:
VecProxy(std::vector<T>& ref1, std::vector<T>& ref2) : v1(ref1), v2(ref2) {}
T& operator[](const size_t& i);
const T& operator[](const size_t& i) const;
const size_t size() const;
};
template<class T>
T& VecProxy<T>::operator[](const size_t& i){
return (i < v1.size()) ? v1[i] : v2[i - v1.size()];
};
template <class T>
const T& VecProxy<T>::operator[](const size_t& i) const{
return (i < v1.size()) ? v1[i] : v2[i - v1.size()];
};
template <class T>
const size_t VecProxy<T>::size() const { return v1.size() + v2.size(); };
AVANTAGE PRINCIPAL
C'est O(1) (temps constant) pour le créer, avec un minimum d'allocation de mémoire supplémentaire. En pratique, c’est une opération rapide, même en considérant des vecteurs énormes, puisque vous remplacez | B | (ou | A | + | B |) élément copie par zéro. En outre, il offre exactement le comportement souhaité.
La concaténation des vecteurs est au moins égale à O (| B |) (lorsque B est ajouté à A), quelle que soit la technique utilisée. Dans votre cas, puisque vous avez l’intention de travailler avec un 3ème vecteur, AB, c’est O (| A | + | B |). En fonction à la fois de la taille des vecteurs et du nombre d'opérations de concaténation nécessaires, cela peut constituer un goulot d'étranglement. L'astuce ci-dessus y fait face.
QUELQUES PRODUITS À CONSIDÉRER
Si vos vecteurs sont triés *, consultez set_union dans <algorithm>.
set_union(A.begin(), A.end(), B.begin(), B.end(), AB.begin());
Il y a un exemple plus complet dans le lien
* merci rlbond
Toutes les solutions sont correctes, mais j’ai trouvé plus facile d’écrire une fonction pour implémenter ceci. comme ça:
template <class T1, class T2>
void ContainerInsert(T1 t1, T2 t2)
{
t1->insert(t1->end(), t2->begin(), t2->end());
}
De cette façon, vous pouvez éviter le placement temporaire comme ceci:
ContainerInsert(vec, GetSomeVector());