Concaténation de deux std:: vecteurs

comment concaténer deux std::vector s?

499
demandé sur emlai 2008-10-14 19:46:01

17 réponses

vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
561
répondu Robert Gamble 2008-10-14 15:48:28

si vous utilisez C++11, et que vous souhaitez déplacer les éléments plutôt que de simplement les copier, Vous pouvez utiliser std:: move_iterator ( http://en.cppreference.com/w/cpp/iterator/move_iterator ) avec insertion (ou copie):

#include <vector>
#include <iostream>
#include <iterator>

int main(int argc, char** argv) {
  std::vector<int> dest{1,2,3,4,5};
  std::vector<int> src{6,7,8,9,10};

  // Move elements from src to dest.
  // src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

  // Print out concatenated vector.
  std::copy(
      dest.begin(),
      dest.end(),
      std::ostream_iterator<int>(std::cout, "\n")
    );

  return 0;
}

ce ne sera pas plus efficace pour l'exemple avec les ints, car les déplacer n'est pas plus efficace que de les copier, mais pour une structure de données avec des mouvements optimisés, il peut éviter de copier l'état inutile:

#include <vector>
#include <iostream>
#include <iterator>

int main(int argc, char** argv) {
  std::vector<std::vector<int>> dest{{1,2,3,4,5}, {3,4}};
  std::vector<std::vector<int>> src{{6,7,8,9,10}};

  // Move elements from src to dest.
  // src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

  return 0;
}

après le déplacement, l'élément src est laissé dans un état indéfini mais sûr à détruire, et ses anciens éléments ont été transférés directement au nouvel élément de la dest à la fin.

128
répondu Alex 2014-05-06 06:11:22

j'utiliserais la fonction insert , quelque chose comme:

vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
122
répondu Tom Ritter 2016-11-23 10:58:57

ou vous pouvez utiliser:

std::copy(source.begin(), source.end(), std::back_inserter(destination));

Ce modèle est utile si les deux vecteurs ne contiennent pas exactement le même type de chose, parce que vous pouvez utiliser quelque chose à la place de std::back_inserter pour passer d'un type à l'autre.

72
répondu Roger Lipscombe 2008-10-15 16:47:39

avec C++11, je préfère ajouter le vecteur b À a:

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

lorsque a et b ne sont pas superposés, et b ne sera plus utilisé.

34
répondu Deqing 2016-11-17 12:28:30
std::vector<int> first;
std::vector<int> second;

first.insert(first.end(), second.begin(), second.end());
32
répondu James Curran 2008-10-14 15:48:37

je préfère un qui est déjà mentionné:

a.insert(a.end(), b.begin(), b.end());

mais si vous utilisez C++11, Il y a une autre façon générique:

a.insert(std::end(a), std::begin(b), std::end(b));

aussi, ne fait pas partie d'une question, mais il est conseillé d'utiliser reserve avant d'Ajouter pour une meilleure performance. Et si vous êtes vecteur concaténateur avec lui-même, sans réserver il échoue, donc vous devriez toujours reserve .


Donc, fondamentalement, ce que vous avez besoin de:

template <typename T>
void Append(std::vector<T>& a, const std::vector<T>& b)
{
    a.reserve(a.size() + b.size());
    a.insert(a.end(), b.begin(), b.end());
}
21
répondu ST3 2016-12-05 09:09:42

vous devez utiliser vecteur:: insérer

v1.insert(v1.end(), v2.begin(), v2.end());
9
répondu Boris 2017-08-08 09:38:02

avec gamme v3 , vous pouvez avoir un paresseux concaténation:

ranges::view::concat(v1, v2)

Démo .

5
répondu Jarod42 2017-08-08 08:49:18

si vous êtes intéressé par une garantie d'exception forte (lorsque le constructeur de copie peut lancer une exception):

template<typename T>
inline void append_copy(std::vector<T>& v1, const std::vector<T>& v2)
{
    const auto orig_v1_size = v1.size();
    v1.reserve(orig_v1_size + v2.size());
    try
    {
        v1.insert(v1.end(), v2.begin(), v2.end());
    }
    catch(...)
    {
        v1.erase(v1.begin() + orig_v1_size, v1.end());
        throw;
    }
}

similaire append_move avec une forte garantie ne peut pas être mis en œuvre en général si le constructeur de mouvement de vector element peut lancer (ce qui est peu probable mais quand même).

4
répondu AlexT 2014-05-06 08:21:33
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
3
répondu instance 2016-12-16 11:57:35

ajoutez celui-ci à votre fichier d'en-tête:

template <typename T> vector<T> concat(vector<T> &a, vector<T> &b) {
    vector<T> ret = vector<T>();
    copy(a.begin(), a.end(), back_inserter(ret));
    copy(b.begin(), b.end(), back_inserter(ret));
    return ret;
}

et l'utiliser de cette façon:

vector<int> a = vector<int>();
vector<int> b = vector<int>();

a.push_back(1);
a.push_back(2);
b.push_back(62);

vector<int> r = concat(a, b);

R contiendra [1,2,62]

2
répondu Stepan Yakovenko 2015-11-11 11:32:45

Voici une solution polyvalente utilisant la sémantique de déplacement C++11:

template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
    if (lhs.empty()) return rhs;
    if (rhs.empty()) return lhs;
    std::vector<T> result {};
    result.reserve(lhs.size() + rhs.size());
    result.insert(result.cend(), lhs.cbegin(), lhs.cend());
    result.insert(result.cend(), rhs.cbegin(), rhs.cend());
    return result;
}

template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, const std::vector<T>& rhs)
{
    lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend());
    return std::move(lhs);
}

template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, std::vector<T>&& rhs)
{
    rhs.insert(rhs.cbegin(), lhs.cbegin(), lhs.cend());
    return std::move(rhs);
}

template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, std::vector<T>&& rhs)
{
    if (lhs.empty()) return std::move(rhs);
    lhs.insert(lhs.cend(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
    return std::move(lhs);
}

noter En quoi cela diffère de append ing à un vector .

2
répondu Daniel 2018-04-05 21:03:44

Un général boost de performance pour concaténer est de vérifier la taille des vecteurs. Et fusionner / insérer le plus petit avec le plus grand.

//vector<int> v1,v2;
if(v1.size()>v2.size()){
    v1.insert(v1.end(),v2.begin(),v2.end());
}else{
    v1.insert(v2.end(),v1.begin(),v1.end());
}
1
répondu Vikramjit Roy 2018-05-08 10:11:39

, Vous pouvez préparer votre propre modèle pour opérateur+:

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

la Prochaine chose -+:

vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
    cout << x << " ";
cout << endl;

cet exemple donne la sortie:

1 2 3 4 5 6 7 8
1
répondu Vladimir U. 2018-07-31 12:43:53

si ce que vous recherchez est une façon d'ajouter un vecteur à un autre après la création, vector::insert est votre meilleur pari, comme cela a été répondu plusieurs fois, par exemple:

vector<int> first = {13};
const vector<int> second = {42};

first.insert(first.end(), second.cbegin(), second.cend());

malheureusement il n'y a aucun moyen de construire un const vector<int> , comme ci-dessus vous devez construire et puis insert .


Si ce que vous cherchez est un conteneur pour la concaténation de ces deux vector<int> s, il peut y avoir quelque chose de mieux disponible pour vous, si:

  1. votre vector contient des primitives
  2. vos primitives contenues sont de taille 32-bit ou plus petit
  3. vous voulez un const conteneur

si tout ce qui précède est vrai, je suggère d'utiliser le basic_string qui est char_type correspond à la taille de la primitive contenue dans votre vector . Vous devez inclure un static_assert dans votre code pour valider ces tailles rester cohérent:

static_assert(sizeof(char32_t) == sizeof(int));

Avec cette tenue de vrai, vous pouvez le faire:

const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());

pour plus d'informations sur les différences entre string et vector vous pouvez regarder ici: https://stackoverflow.com/a/35558008/2642059

pour un exemple en direct de ce code vous pouvez regarder ici: http://ideone.com/7Iww3I

0
répondu Jonathan Mee 2017-05-23 12:10:41

pour être honnête, vous pourriez concaténer rapidement deux vecteurs par des éléments de copie de deux vecteurs dans l'autre ou tout simplement ajouter un de deux vecteurs!. Cela dépend de votre objectif.

Méthode 1: Attribuer un nouveau vecteur avec sa taille est la somme de deux vecteurs de taille.

vector<int> concat_vector = vector<int>();
concat_vector.setcapacity(vector_A.size() + vector_B.size());
// Loop for copy elements in two vectors into concat_vector

Méthode 2: ajouter le vecteur A en ajoutant / insérant des éléments du vecteur B.

// Loop for insert elements of vector_B into vector_A with insert() 
function: vector_A.insert(vector_A .end(), vector_B.cbegin(), vector_B.cend());
0
répondu nvnhcmus 2017-08-29 13:50:14