Concatenar dos std :: vectores

¿Cómo concateno dos std :: vector s?

469
@lecaruyer Te das cuenta de que acabas de marcar una pregunta que se hizo dos años antes como duplicado
agregado el autor eshirima, fuente
@FauChristian: No, no puede haber un uso desde el punto de vista de la eficiencia. La memoria vectorial debe ser continua, por lo que lo que se sugiere es imposible. Si quisieras "compartir algo sofisticado de la gestión de los nodos", y si cambiases la clase vectorial de esa forma, terminarías con una deque. Incluso entonces es muy difícil reutilizar la memoria de la manera sugerida, aunque comenzaría a ser un poco más factible. No creo que esté implementado actualmente. Lo principal es que en tal intercambio de nodos de gestión (un deque) el nodo final puede estar parcialmente vacío.
agregado el autor Cookie, fuente
Las respuestas dadas en realidad no concatenan. Añaden una copia. Puede haber un uso (para el punto de vista de la eficiencia) para crear un método de concatenación std :: vector, sin embargo, requeriría un intercambio sofisticado de la administración de los nodos y esa es probablemente la razón por la que no se ha hecho.
agregado el autor FauChristian, fuente
¿Soy el único que se pregunta por qué esto no se implementa como a + b o a.concat (b) en la biblioteca estándar? Tal vez la implementación predeterminada no sea óptima, pero cada concatenación de matriz no necesita ser micro-optimizada
agregado el autor oseiskar, fuente

16 Respuestas

vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
531
agregado
Si ha concatenado varios vectores en uno, ¿es útil llamar primero a reserve en el vector de destino?
agregado el autor Faheem Mitha, fuente
@Aidin veo. Gracias por la aclaración.
agregado el autor Faheem Mitha, fuente
@ Khaur: Es horrible hasta el punto que es difícil de creer. Es muy trivial que una implementación detecte que los iteradores son de acceso aleatorio, calcule el tamaño y reserve previamente el espacio necesario. Creo que MSFT incluso hace eso para los iteradores directos.
agregado el autor Mooing Duck, fuente
@AlexanderRafferty: solo si vector1.capacity ()> = 2 * vector1.size() . Que es atípico a menos que haya llamado a std :: vector :: reserve() . De lo contrario, el vector se reasignará, invalidando los iteradores pasados ​​como parámetros 2 y 3.
agregado el autor Drew Dormann, fuente
Tengo una pregunta. ¿Funcionará esto si vector1 y vector2 son los mismos vectores?
agregado el autor Alexander Rafferty, fuente
Solo agregaría código para obtener primero el número de elementos que tiene cada vector, y establecer que el vector1 sea el que tenga el mayor. Si lo haces, harás muchas copias innecesarias.
agregado el autor Joe Pineda, fuente
Es una lástima que no haya una expresión más sucinta en la biblioteca estándar. .concat o + = o algo
agregado el autor nmr, fuente
@FaheemMitha: dado que los argumentos de insert son vectores, ya se sabe cuántos elementos están adelante y se manejará por sí mismo. Si insertáramos otras cosas como array, era útil reservar el espacio primero.
agregado el autor Aidin, fuente
@MooingDuck Tienes razón, eché de menos al despachador y pensé que la versión del iterador de entrada aplicaba para todos los tipos de iteradores. La versión del iterador directo hace muchas más cosas. Gracias por señalarlo, eliminé mi comentario inicial para que no aparezca sin el tuyo.
agregado el autor Khaur, fuente

Utilizaría la función de inserción , algo así como:

vector a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
112
agregado

Si está utilizando C ++ 11 y desea mover los elementos en lugar de simplemente copiarlos, puede usar std :: move_iterator ( http://en.cppreference.com/w/cpp/iterator/move_iterator ) junto con insertar (o copiar):

#include 
#include 
#include 

int main(int argc, char** argv) {
  std::vector dest{1,2,3,4,5};
  std::vector 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(std::cout, "\n")
    );

  return 0;
}

Esto no será más eficiente para el ejemplo con ints, ya que moverlos no es más eficiente que copiarlos, pero para una estructura de datos con movimientos optimizados, puede evitar copiar el estado innecesario:

#include 
#include 
#include 

int main(int argc, char** argv) {
  std::vector> dest{{1,2,3,4,5}, {3,4}};
  std::vector> 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;
}

Después del movimiento, el elemento de src queda en un estado indefinido pero seguro de destruir, y sus elementos anteriores se transfirieron directamente al nuevo elemento de dest al final.

112
agregado
El método std :: make_move_iterator() me ayudó a tratar de concatenar std :: vectores de std :: unique_ptr.
agregado el autor Knitschi, fuente

O podrías usar:

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

Este patrón es útil si los dos vectores no contienen exactamente el mismo tipo de cosa, porque puede usar algo en lugar de std :: back_inserter para convertir de un tipo a otro.

70
agregado
@Yogesh: concedido, pero no hay nada que te impida llamar primero a reserve . La razón por la cual std :: copy a veces es útil es si usted quiere usar algo que no sea back_inserter .
agregado el autor Roger Lipscombe, fuente
Cuando dice "asignaciones múltiples", eso es cierto, pero el número de asignaciones es en el peor de los casos (número de entradas agregadas), lo que significa que el costo de agregar una entrada es constante en la cantidad de entradas agregadas. (Básicamente, no te preocupes, a menos que los perfiles muestren que necesitas una reserva).
agregado el autor Martin Bonner, fuente
Es posible que desee utilizar std :: transform para hacer esto en su lugar.
agregado el autor Martin Broadhurst, fuente
el método de copia no es una buena manera. Llamará a push_back varias veces, lo que significa que si se tienen que insertar muchos elementos, esto podría significar múltiples reasignaciones. es mejor usar inserción ya que la implementación del vector podría hacer alguna optimización para evitar reasignaciones. podría reservar memoria antes de comenzar a copiar
agregado el autor Yogesh Arora, fuente
std::vector first;
std::vector second;

first.insert(first.end(), second.begin(), second.end());
30
agregado

Con C ++ 11, preferiría seguir para anexar el vector b a a:

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

cuando a y b no se superponen, y b ya no se usará.

27
agregado
@MartinBonner Gracias por mencionar eso. Probablemente debería volver al antiguo método insert que es más seguro.
agregado el autor Deqing, fuente
solo agregue la siguiente línea de encabezado begin: #include
agregado el autor Manohar Reddy Poreddy, fuente
Comportamiento indefinido si a realmente es b (lo cual está bien si sabes que nunca puede suceder, pero vale la pena tenerlo en cuenta en el código de propósito general).
agregado el autor Martin Bonner, fuente
Ah, el OTRO estándar :: movimiento. Muy confuso la primera vez que lo ves.
agregado el autor xaxxon, fuente

Prefiero uno que ya se mencionó:

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

Pero si usa C ++ 11, hay una forma más genérica:

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

Además, no forma parte de una pregunta, pero es aconsejable utilizar reserve antes de agregarlo para un mejor rendimiento. Y si concatenas el vector consigo mismo, sin reservar, falla, por lo que siempre debes reservar .


Entonces, básicamente, lo que necesitas:

template 
void Append(std::vector& a, const std::vector& b)
{
    a.reserve(a.size() + b.size());
    a.insert(a.end(), b.begin(), b.end());
}
18
agregado
@Asu ADL solo agregará std :: si el tipo de a proviene de std , lo que frustra el aspecto genérico.
agregado el autor Potatoswatter, fuente
std :: se deduce a través de búsqueda dependiente de argumentos . end (a) será suficiente.
agregado el autor Asu, fuente
buen punto. en este caso es un vector así que funcionaría de todos modos, pero sí, esa es una mejor solución.
agregado el autor Asu, fuente

Debería utilizar vector :: insert

v1.insert(v1.end(), v2.begin(), v2.end());
5
agregado

Si está interesado en una garantía de excepción fuerte (cuando el constructor de copia puede lanzar una excepción):

template
inline void append_copy(std::vector& v1, const std::vector& 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;
    }
}

Similar append_move con una garantía fuerte no se puede implementar en general si el constructor de movimientos del elemento vectorial puede lanzar (lo cual es poco probable pero aún así).

4
agregado
insert ya maneja esto. Además, esta llamada a erase es equivalente a un resize .
agregado el autor Potatoswatter, fuente
¿No es posible que también se lance v1.erase (... ?
agregado el autor camelCase, fuente
vector v1 = {1, 2, 3, 4, 5};
vector v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
3
agregado
Si bien este fragmento de código puede resolver el problema, no explica por qué o cómo responde la pregunta. Por favor, incluya una explicación para su código , ya que eso realmente ayuda a mejorar la calidad de su publicación. Marcadores/revisores: ¡Para respuestas de solo código como este, downvote, no eliminar! (Nota: esta respuesta puede ser lo suficientemente simple como para hacer que una explicación, y por lo tanto downvotes, sea innecesaria. Puede agregar una expli
agregado el autor Scott Weldon, fuente

Agregue este a su archivo de encabezado:

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

y úsalo de esta manera:

vector a = vector();
vector b = vector();

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

vector r = concat(a, b);

r contendrá [1,2,62]

2
agregado
No sé por qué esto fue votado negativamente. Puede que no sea la forma más eficiente de hacerlo, pero no está mal y es efectivo.
agregado el autor leeor_net, fuente

Con rango v3 , es posible que tenga una concatenación floja :

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

Demo.

2
agregado

Aquí hay una solución de uso general que usa la semántica de movimientos de C ++ 11:

template 
std::vector concat(const std::vector& lhs, const std::vector& rhs)
{
    if (lhs.empty()) return rhs;
    if (rhs.empty()) return lhs;
    std::vector 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 
std::vector concat(std::vector&& lhs, const std::vector& rhs)
{
    lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend());
    return std::move(lhs);
}

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

template 
std::vector concat(std::vector&& lhs, std::vector&& 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);
}

Tenga en cuenta que esto difiere de append en un vector .

1
agregado

Si lo que está buscando es una forma de agregar un vector a otro después de la creación, vector :: insert es su mejor apuesta, como se ha respondido varias veces, por ejemplo:

vector first = {13};
const vector second = {42};

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

Sadly there's no way to construct a const vector, as above you must construct and then insert.


If what you're actually looking for is a container to hold the concatenation of these two vectors, there may be something better available to you, if:

  1. Su vector contiene elementos primitivos
  2. Sus primitivas contenidas son del tamaño de 32 bits o menos
  3. Quiere un contenedor const

Si todo lo anterior es cierto, te sugiero usar la basic_string que es char_type coincide con el tamaño de la primitiva contenida en su vector . Debe incluir un static_assert en su código para Valide que estos tamaños se mantengan consistentes:

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

Con esto cierto, puedes hacer lo siguiente:

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

For more information on the differences between string and vector you can look here: https://stackoverflow.com/a/35558008/2642059

For a live example of this code you can look here: http://ideone.com/7Iww3I

0
agregado

Para ser honesto, puedes concatenar rápidamente dos vectores copiando elementos de dos vectores en el otro o solo anexando uno de dos vectores. Depende de tu objetivo

Method 1: Assign new vector with its size is the sum of two original vectors' size.

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

Method 2: Append vector A by adding/inserting elements of vector 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
agregado
¿Qué agrega su respuesta que no se haya proporcionado en otras respuestas?
agregado el autor Mat, fuente
Si los vectores originales ya no son necesarios después, puede ser mejor usar std :: move_iterator para que los elementos se muevan en lugar de copiarse. (Consulte en.cppreference.com/w/cpp/iterator/move_iterator ) .
agregado el autor tmlen, fuente
@Mat: personajes en negrita.
agregado el autor marcv81, fuente

Un impulso de rendimiento general para la concatenación consiste en verificar el tamaño de los vectores. Y fusiona/inserta el más pequeño con el más grande.

//vector v1,v2;
if(v1.size()>v2.size()){
    v1.insert(v1.end(),v2.begin(),v2.end());
}else{
    v1.insert(v2.end(),v1.begin(),v1.end());
}
0
agregado