Las respuestas dadas en realidad no se concatenan. Anexan una copia. Puede ser útil (para el punto de vista de la eficiencia) crear un método de concatenación std :: vector, sin embargo, requeriría un intercambio sofisticado de la gestión de los nodos y probablemente es por eso que no se ha hecho.
FauChristian
8
@FauChristian: No, puede que no haya un uso desde el punto de vista de la eficiencia. La memoria del vector debe ser continua, por lo que lo sugerido es imposible. Si desea "un intercambio sofisticado de la gestión de los nodos", y si fuera a cambiar la clase de vectores de esa manera, terminaría con una disminución. Aun así, 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 al compartir tales nodos de administración (una deque), el nodo final podría estar parcialmente vacío.
Cookie
44
@lecaruyer Te das cuenta de que acabas de marcar una pregunta que se hizo dos años antes como un duplicado
eshirima
99
¿Soy el único que se pregunta por qué esto no se implementa como a + bo a.concat(b)en la biblioteca estándar? Tal vez la implementación predeterminada sería subóptima, pero no es necesario que cada concatenación de matriz sea micro-optimizada
oseiskar
99
años de evolución, la sobrecarga de operadores más avanzada de cualquier lenguaje convencional, un sistema de plantillas que duplica la complejidad del lenguaje y, sin embargo, la respuesta no es v = v1 + v2;
Solo agregaría código para obtener primero el número de elementos que contiene cada vector, y establecería que vector1 sea el que tenga el mayor. Si no lo hace, está haciendo muchas copias innecesarias.
Joe Pineda
34
Tengo una pregunta. ¿Funcionará esto si vector1 y vector2 son los mismos vectores?
Alexander Rafferty
66
Si ha concatenado varios vectores en uno, ¿es útil llamar reserveprimero al vector de destino?
Faheem Mitha
33
@AlexanderRafferty: solo si vector1.capacity() >= 2 * vector1.size(). Lo cual es atípico a menos que haya llamado std::vector::reserve(). De lo contrario, el vector se reasignará, invalidando los iteradores pasados como parámetros 2 y 3.
Drew Dormann
28
Es una pena que no haya una expresión más sucinta en la biblioteca estándar. .concato +=algo así
RMN
193
Si está utilizando C ++ 11 y desea mover los elementos en lugar de simplemente copiarlos, puede usar std::move_iteratorjunto con insertar (o copiar):
#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"));return0;}
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 estados innecesarios:
#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()));return0;}
Después del movimiento, el elemento src se deja en un estado indefinido pero seguro para destruir, y sus elementos anteriores se transfirieron directamente al nuevo elemento de dest al final.
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.
El método de copia no es una buena manera. Llamará a push_back varias veces, lo que significa que si se deben insertar muchos elementos, esto podría significar múltiples reasignaciones. es mejor usar insert 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
Yogesh Arora
77
@Yogesh: concedido, pero no hay nada que te impida llamar reserveprimero. La razón a std::copyveces es útil si desea utilizar algo distinto de back_inserter.
Roger Lipscombe
Cuando dice "asignaciones múltiples", eso es cierto, pero el número de asignaciones es en el peor registro (número de entradas agregadas), lo que significa que el costo de agregar una entrada es constante en el número de entradas agregadas. (Básicamente, no se preocupe por eso a menos que el perfil muestre que necesita una reserva).
Martin Bonner apoya a Monica el
Es posible que desee utilizar std :: transform para hacer esto en su lugar.
Comportamiento indefinido si a en realidad es b (lo cual está bien si sabe que eso nunca puede suceder, pero vale la pena tenerlo en cuenta en el código de propósito general).
Martin Bonner apoya a Monica el
1
@ MartinBonner Gracias por mencionar eso. Probablemente debería volver a la vieja insertforma que es más segura.
Deqing
15
Ah, el OTRO std :: move. Bastante confuso la primera vez que lo ves.
xaxxon
1
¿Es esto diferente de insert()con move_iterators? ¿Si es así, cómo?
GPhilo
1
He agregado una nota sobre lo std::moveque estamos hablando aquí, ya que la mayoría de las personas no conocen esta sobrecarga. Espero que sea una mejora.
Además, no es parte de una pregunta, pero es aconsejable usar reserveantes de agregar para un mejor rendimiento. Y si está concatenando un vector consigo mismo, sin reservarlo falla, por lo que siempre debería hacerlo reserve.
@Asu ADL solo se agregará std::si el tipo de aproviene std, lo que anula el aspecto genérico.
Potatoswatter
buen punto. en este caso es un vector, por lo que funcionaría de todos modos, pero sí, esa es una mejor solución.
Asu
std :: begin () / end () se agregaron para colecciones (como matrices) que no las tienen como funciones miembro. Pero las matrices tampoco tienen una función miembro insert (), y hace la pregunta "¿Hay una colección con insert () pero sin begin () (que funciona con std :: begin ())?"
James Curran
15
Con el rango v3 , puede tener una concatenación perezosa :
El código de muestra es incorrecto. v1.insert(v2.end()...está utilizando un iterador en v2para especificar la posición en v1.
David Stone
También puede usar un intercambio rápido. @DavidStone Lo edité para que se pueda cambiar el orden de concat. ¿Es posible agregar al comienzo de un vector?
qwr
Puede insertar al principio, pero será más lento. Sin embargo, para realmente "concatenar", el orden generalmente importa, así que eso es lo que debe hacer.
David Stone
7
Si desea poder concatenar vectores de forma concisa, puede sobrecargar el +=operador.
Similar append_movecon una fuerte garantía no se puede implementar en general si el constructor de movimiento del elemento vector puede lanzar (lo cual es poco probable pero aún así).
No creo que sea más fácil de usar que std::vector::insert, pero hace algo diferente: fusionar dos rangos en un nuevo rango versus insertar un vector al final de otro. Vale la pena mencionar en la respuesta?
jb
4
Si su objetivo es simplemente iterar sobre el rango de valores para fines de solo lectura, una alternativa es envolver ambos vectores alrededor de un proxy (O (1)) en lugar de copiarlos (O (n)), para que se vean rápidamente como una sola, contigua.
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 de su código , como que realmente ayuda a mejorar la calidad de su puesto. Señaladores / revisores: para respuestas de solo código, como esta, voto negativo, ¡no las borre! (Nota: esta respuesta en realidad puede ser lo suficientemente simple como para hacer una explicación, y por lo tanto votos negativos, innecesarios. Es posible que aún desee agregar una explicación para evitar más banderas NAA / VLQ.)
Scott Weldon
2
He implementado esta función que concatena cualquier cantidad de contenedores, pasando de rvalue-references y copiando lo contrario
namespaceinternal{// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if// appropriatetemplate<typenameTarget,typenameHead,typename...Tail>voidAppendNoReserve(Target* target,Head&& head,Tail&&... tail){// Currently, require each homogenous inputs. If there is demand, we could probably implement a// version that outputs a vector whose value_type is the common_type of all the containers// passed to it, and call it ConvertingConcatenate.static_assert(
std::is_same_v<typename std::decay_t<Target>::value_type,typename std::decay_t<Head>::value_type>,"Concatenate requires each container passed to it to have the same value_type");ifconstexpr(std::is_lvalue_reference_v<Head>){
std::copy(head.begin(), head.end(), std::back_inserter(*target));}else{
std::move(head.begin(), head.end(), std::back_inserter(*target));}ifconstexpr(sizeof...(Tail)>0){AppendNoReserve(target, std::forward<Tail>(tail)...);}}template<typenameHead,typename...Tail>size_tTotalSize(constHead& head,constTail&... tail){ifconstexpr(sizeof...(Tail)>0){return head.size()+TotalSize(tail...);}else{return head.size();}}}// namespace internal/// Concatenate the provided containers into a single vector. Moves from rvalue references, copies/// otherwise.template<typenameHead,typename...Tail>autoConcatenate(Head&& head,Tail&&... tail){size_t totalSize =internal::TotalSize(head, tail...);
std::vector<typename std::decay_t<Head>::value_type> result;
result.reserve(totalSize);internal::AppendNoReserve(&result, std::forward<Head>(head), std::forward<Tail>(tail)...);return result;}
Si lo que está buscando es una forma de agregar un vector a otro después de la creación, vector::insertes su mejor opción, como se ha respondido varias veces, por ejemplo:
vector<int> first ={13};const vector<int> second ={42};
first.insert(first.end(), second.cbegin(), second.cend());
Lamentablemente no hay forma de construir un const vector<int>, como se debe construir arriba y luego insert.
Si lo que realmente está buscando es un contenedor para contener la concatenación de estos dos vector<int>s, puede haber algo mejor disponible para usted, si:
Tu vectorcontiene primitivas
Sus primitivas contenidas son de 32 bits o menos
Quieres un constcontenedor
Si todo lo anterior es cierto, te sugiero que uses basic_stringquién char_typecoincide con el tamaño de la primitiva contenida en tu vector. Debe incluir un static_asserten su código para validar que estos tamaños se mantengan consistentes:
Esta solución puede ser un poco complicada, pero boost-rangetambién tiene otras cosas buenas que ofrecer.
#include<iostream>#include<vector>#include<boost/range/algorithm/copy.hpp>int main(int,char**){
std::vector<int> a ={1,2,3};
std::vector<int> b ={4,5,6};
boost::copy(b, std::back_inserter(a));for(auto& iter : a){
std::cout << iter <<" ";}return EXIT_SUCCESS;}
A menudo, la intención es combinar el vector a y bsimplemente iterar sobre él haciendo alguna operación. En este caso, existe la ridícula joinfunción simple .
#include<iostream>#include<vector>#include<boost/range/join.hpp>#include<boost/range/algorithm/copy.hpp>int main(int,char**){
std::vector<int> a ={1,2,3};
std::vector<int> b ={4,5,6};
std::vector<int> c ={7,8,9};// Just creates an iteratorfor(auto& iter : boost::join(a, boost::join(b, c))){
std::cout << iter <<" ";}
std::cout <<"\n";// Can also be used to create a copy
std::vector<int> d;
boost::copy(boost::join(a, boost::join(b, c)), std::back_inserter(d));for(auto& iter : d){
std::cout << iter <<" ";}return EXIT_SUCCESS;}
Para vectores grandes, esto podría ser una ventaja, ya que no hay copia. También se puede usar para copiar y generalizar fácilmente en más de un contenedor.
Por alguna razón no hay nada como boost::join(a,b,c), lo que podría ser razonable.
Para ser honesto, ¡podría concatenar rápidamente dos vectores copiando elementos de dos vectores en el otro o simplemente agregar uno de los dos vectores! Depende de tu puntería.
Método 1: asignar un nuevo vector con su tamaño es la suma del tamaño de dos vectores originales.
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étodo 2: Agregue el vector A agregando / insertando elementos del 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());
¿Qué agrega su respuesta que aún no se ha proporcionado en otras respuestas?
Mat
13
@ Mat: caracteres en negrita.
marcv81
Si los vectores originales ya no son necesarios después, puede ser mejor usarlos std::move_iteratorpara que los elementos se muevan en lugar de copiarse. (ver en.cppreference.com/w/cpp/iterator/move_iterator ).
a + b
oa.concat(b)
en la biblioteca estándar? Tal vez la implementación predeterminada sería subóptima, pero no es necesario que cada concatenación de matriz sea micro-optimizadaRespuestas:
fuente
reserve
primero al vector de destino?vector1.capacity() >= 2 * vector1.size()
. Lo cual es atípico a menos que haya llamadostd::vector::reserve()
. De lo contrario, el vector se reasignará, invalidando los iteradores pasados como parámetros 2 y 3..concat
o+=
algo asíSi está utilizando C ++ 11 y desea mover los elementos en lugar de simplemente copiarlos, puede usar
std::move_iterator
junto con insertar (o copiar):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 estados innecesarios:
Después del movimiento, el elemento src se deja en un estado indefinido pero seguro para destruir, y sus elementos anteriores se transfirieron directamente al nuevo elemento de dest al final.
fuente
std::move(src.begin(), src.end(), back_inserter(dest))
?Me gustaría utilizar la función de inserción , algo así como:
fuente
O podrías usar:
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.
fuente
reserve
primero. La razón astd::copy
veces es útil si desea utilizar algo distinto deback_inserter
.Con C ++ 11, preferiría seguir para agregar el vector b a:
cuando
a
yb
no se superponen, yb
ya no se va a usar.Esto es
std::move
de<algorithm>
, no el habitualstd::move
de<utility>
.fuente
insert
forma que es más segura.insert()
conmove_iterator
s? ¿Si es así, cómo?std::move
que estamos hablando aquí, ya que la mayoría de las personas no conocen esta sobrecarga. Espero que sea una mejora.fuente
Prefiero uno que ya se menciona:
Pero si usa C ++ 11, hay una forma más genérica:
Además, no es parte de una pregunta, pero es aconsejable usar
reserve
antes de agregar para un mejor rendimiento. Y si está concatenando un vector consigo mismo, sin reservarlo falla, por lo que siempre debería hacerloreserve
.Básicamente lo que necesitas:
fuente
std::
se deduce mediante una búsqueda dependiente de argumentos .end(a)
será suficiente.std::
si el tipo dea
provienestd
, lo que anula el aspecto genérico.Con el rango v3 , puede tener una concatenación perezosa :
Demostración .
fuente
Deberías usar vector :: insert
fuente
Un aumento de rendimiento general para concatenar es verificar el tamaño de los vectores. E fusionar / insertar el más pequeño con el más grande.
fuente
v1.insert(v2.end()...
está utilizando un iterador env2
para especificar la posición env1
.Si desea poder concatenar vectores de forma concisa, puede sobrecargar el
+=
operador.Entonces puedes llamarlo así:
fuente
Si está interesado en una garantía de excepción fuerte (cuando el constructor de copias puede lanzar una excepción):
Similar
append_move
con una fuerte garantía no se puede implementar en general si el constructor de movimiento del elemento vector puede lanzar (lo cual es poco probable pero aún así).fuente
v1.erase(...
lanzar también?insert
Ya maneja esto. Además, esta llamada aerase
es equivalente a aresize
.Agregue este a su archivo de encabezado:
y úsalo de esta manera:
r contendrá [1,2,62]
fuente
Aquí hay una solución de uso general que utiliza semántica de movimiento C ++ 11:
Observe cómo esto difiere de
append
ing a avector
.fuente
Puede preparar su propia plantilla para el operador +:
Lo siguiente: solo usa +:
Este ejemplo da salida:
fuente
T operator+(const T & a, const T & b)
es peligroso, es mejor usarlovector<T> operator+(const vector<T> & a, const vector<T> & b)
.Existe un algoritmo
std::merge
de C ++ 17 , que es muy fácil de usar,A continuación se muestra el ejemplo:
fuente
std::vector::insert
, pero hace algo diferente: fusionar dos rangos en un nuevo rango versus insertar un vector al final de otro. Vale la pena mencionar en la respuesta?Si su objetivo es simplemente iterar sobre el rango de valores para fines de solo lectura, una alternativa es envolver ambos vectores alrededor de un proxy (O (1)) en lugar de copiarlos (O (n)), para que se vean rápidamente como una sola, contigua.
Consulte https://stackoverflow.com/a/55838758/2379625 para obtener más detalles, incluida la implementación 'VecProxy', así como los pros y los contras.
fuente
fuente
He implementado esta función que concatena cualquier cantidad de contenedores, pasando de rvalue-references y copiando lo contrario
fuente
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 opción, como se ha respondido varias veces, por ejemplo:Lamentablemente no hay forma de construir un
const vector<int>
, como se debe construir arriba y luegoinsert
.Si lo que realmente está buscando es un contenedor para contener la concatenación de estos dos
vector<int>
s, puede haber algo mejor disponible para usted, si:vector
contiene primitivasconst
contenedorSi todo lo anterior es cierto, te sugiero que uses
basic_string
quiénchar_type
coincide con el tamaño de la primitiva contenida en tuvector
. Debe incluir unstatic_assert
en su código para validar que estos tamaños se mantengan consistentes:Con esto es cierto, puedes hacer:
Para obtener más información sobre las diferencias entre
string
yvector
puede mirar aquí: https://stackoverflow.com/a/35558008/2642059Para ver un ejemplo en vivo de este código, puede consultar aquí: http://ideone.com/7Iww3I
fuente
Esta solución puede ser un poco complicada, pero
boost-range
también tiene otras cosas buenas que ofrecer.A menudo, la intención es combinar el vector
a
yb
simplemente iterar sobre él haciendo alguna operación. En este caso, existe la ridículajoin
función simple .Para vectores grandes, esto podría ser una ventaja, ya que no hay copia. También se puede usar para copiar y generalizar fácilmente en más de un contenedor.
Por alguna razón no hay nada como
boost::join(a,b,c)
, lo que podría ser razonable.fuente
Puede hacerlo con algoritmos STL pre-implementados usando una plantilla para un uso de tipo polimórfico.
Puede borrar el segundo vector si no desea usarlo más (
clear()
método).fuente
Para ser honesto, ¡podría concatenar rápidamente dos vectores copiando elementos de dos vectores en el otro o simplemente agregar uno de los dos vectores! Depende de tu puntería.
Método 1: asignar un nuevo vector con su tamaño es la suma del tamaño de dos vectores originales.
Método 2: Agregue el vector A agregando / insertando elementos del vector B.
fuente
std::move_iterator
para que los elementos se muevan en lugar de copiarse. (ver en.cppreference.com/w/cpp/iterator/move_iterator ).setcapacity
? ¿Qué esfunction:
?resize
método.