As respostas dadas na verdade não concatenam. Eles anexam uma cópia. Pode haver um uso (para o ponto de vista da eficiência) para criar um método de concatenação std :: vector, no entanto, seria necessário um compartilhamento sofisticado do gerenciamento dos nós e é provavelmente por isso que não foi feito.
FauChristian
8
@FauChristian: Não, pode não ser útil do ponto de vista da eficiência. A memória vetorial deve ser contínua; portanto, o que lhe é sugerido é impossível. Se você quisesse "algum compartilhamento sofisticado do gerenciamento dos nós" e se mudasse a classe de vetores dessa maneira, acabaria com um deque. Mesmo assim, é muito difícil reutilizar a memória da maneira sugerida, embora isso comece a ser um pouco mais viável. Não acho que esteja implementado atualmente. O principal é que nesse compartilhamento de nós de gerenciamento (um deque) o nó final pode estar parcialmente vazio.
Cookie
4
@lecaruyer Você percebe que você só marcou uma pergunta que foi feita dois anos antes como uma duplicata
eshirima
9
Eu sou o único a perguntar por que isso não é implementado como a + bou a.concat(b)na biblioteca padrão? Talvez a implementação padrão não ser o melhor, mas cada concatenação de matriz não precisa ser micro-otimizado
oseiskar
9
anos de evolução, a sobrecarga de operador mais avançada de qualquer linguagem convencional, um sistema de modelos que dobra a complexidade da linguagem e, no entanto, a resposta não é v = v1 + v2;
Eu adicionaria apenas o código para obter primeiro o número de elementos que cada vetor contém e definir o vetor1 como aquele que contém o maior. Caso contrário, você está fazendo muitas cópias desnecessárias.
Joe Pineda
34
Eu tenho uma pergunta. Isso funcionará se o vetor1 e o vetor2 forem os mesmos vetores?
Alexander Rafferty
6
Se você concatenou vários vetores para um, é útil chamar reserveo vetor de destino primeiro?
Faheem Mitha
33
@AlexanderRafferty: Somente se vector1.capacity() >= 2 * vector1.size(). O que é atípico, a menos que você tenha telefonado std::vector::reserve(). Caso contrário, o vector vai realocar, invalidar os iterators passados como parâmetros 2 e 3.
Desenhou Dormann
28
É uma pena que não haja uma expressão mais sucinta na biblioteca padrão. .concatou +=algo parecido
nmr
193
Se você estiver usando o C ++ 11 e desejar mover os elementos, em vez de apenas copiá-los, poderá usar std::move_iteratorjunto com insert (ou copy):
#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;}
Isso não será mais eficiente para o exemplo com ints, pois movê-los não é mais eficiente do que copiá-los, mas para uma estrutura de dados com movimentos otimizados, ele pode evitar a cópia de um estado desnecessário:
#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;}
Após a mudança, o elemento src é deixado em um estado indefinido, mas seguro para destruir, e seus elementos anteriores foram transferidos diretamente para o novo elemento do dest no final.
Esse padrão é útil se os dois vetores não contêm exatamente o mesmo tipo de coisa, porque você pode usar algo em vez de std :: back_inserter para converter de um tipo para outro.
o método de cópia não é uma maneira tão boa. Ele chamará push_back várias vezes, o que significa que, se muitos elementos precisarem ser inseridos, isso pode significar várias realocações. é melhor usar o insert, pois a implementação do vetor poderia fazer alguma otimização para evitar realocações. pode reservar memória antes de iniciar a cópia
Yogesh Arora
7
@ Yogesh: concedido, mas não há nada para você ligar reserveprimeiro. O motivo std::copyàs vezes é útil é se você deseja usar algo diferente back_inserter.
22410 Roger Lipscombe
Quando você diz "várias alocações", isso é verdade - mas o número de alocações é no pior log (número de entradas adicionadas) - o que significa que o custo de adicionar uma entrada é constante no número de entradas adicionadas. (Basicamente, não se preocupe, a menos que o perfil mostre que você precisa de uma reserva).
Comportamento indefinido se a for realmente b (o que é bom se você sabe que isso nunca pode acontecer - mas vale a pena estar ciente do código de uso geral).
Martin Bonner apoia Monica
1
@ Martinartner Obrigado por mencionar isso. Provavelmente eu deveria voltar ao insertcaminho antigo , que é mais seguro.
Deqing
15
Ah, o OTHER std :: move. Bastante confuso a primeira vez que você o vê.
Xaxxon
1
Isso é diferente de insert()com move_iterators? Se sim, como?
GPHilo #
1
Adicionei uma observação sobre o std::moveque estamos falando aqui, pois a maioria das pessoas não conhece essa sobrecarga. Espero que seja uma melhoria.
Além disso, não faz parte de uma pergunta, mas é recomendável usá-lo reserveantes de anexá-lo para obter um melhor desempenho. E se você estiver concatenando o vetor consigo mesmo, sem reservar, ele falhará, então você sempre deve reserve.
O @Asu ADL só adicionará std::se o tipo de origem avier std, o que anula o aspecto genérico.
Potatoswatter
bom ponto. nesse caso, é um vetor, portanto funcionaria de qualquer maneira, mas sim, é uma solução melhor.
Asu
std :: begin () / end () foram adicionados para coleções (como matrizes) que não as possuem como funções membro. Mas matrizes também não têm uma função de membro insert () e chama a pergunta "Existe uma coleção com um insert () mas sem begin () (que funciona com o std :: begin ())?"
21818 James Curran #
15
Com o intervalo v3 , você pode ter uma concatenação lenta :
Tão simples, mas nunca pensei nisso dessa maneira!
Zimano 15/03/19
2
O código de exemplo está incorreto. v1.insert(v2.end()...está a utilizar uma iteração para v2a determinar a posição em v1.
1855 David Stone
Você também pode usar uma troca rápida. @ DavidStone Eu editei para que a ordem da concat fosse alterada. É possível adicionar ao início de um vetor?
Q9
Você pode inserir no início, mas isso será mais lento. Para realmente "concatenar", no entanto, a ordem normalmente importa, e é isso que você precisa fazer.
David Stone
7
Se você deseja concatenar vetores de forma concisa, pode sobrecarregar o +=operador.
Similar append_movecom garantia forte não pode ser implementado em geral se o construtor de movimento do elemento vetorial puder lançar (o que é improvável, mas ainda).
Eu não acho que seja mais fácil de usar do que isso std::vector::insert, mas faz algo diferente: mesclar dois intervalos em um novo intervalo versus inserir um vetor no final de outro. Vale mencionar na resposta?
jb
4
Se seu objetivo é simplesmente iterar o intervalo de valores para fins somente leitura, uma alternativa é agrupar os dois vetores em torno de um proxy (O (1)) em vez de copiá-los (O (n)), para que sejam vistos imediatamente como um único, contíguo.
Embora esse trecho de código possa resolver o problema, ele não explica por que ou como responde à pergunta. Por favor incluir uma explicação para o seu código , como o que realmente ajuda a melhorar a qualidade do seu post. Sinalizadores / revisores: para respostas somente de código como esta, com voto negativo, não exclua! (. Nota: Esta resposta pode realmente ser bastante simples de fazer uma explicação, e assim downvotes, desnecessária Você ainda pode querer adicionar uma explicação para evitar mais bandeiras NAA / VLQ.)
Scott Weldon
2
Eu implementei essa função que concatena qualquer número de contêineres, movendo-se de rvalue-reference e copiando de outra forma
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;}
Se o que você procura é uma maneira de anexar um vetor a outro após a criação, vector::inserté sua melhor aposta, como já foi respondido várias vezes, por exemplo:
vector<int> first ={13};const vector<int> second ={42};
first.insert(first.end(), second.cbegin(), second.cend());
Infelizmente, não há como construir um const vector<int>, como acima você deve construir e depois insert.
Se o que você está realmente procurando é um contêiner para conter a concatenação desses dois vector<int>s, pode haver algo melhor disponível para você, se:
O seu vectorcontém primitivas
Suas primitivas contidas são de tamanho 32 bits ou menor
Você quer um constcontêiner
Se tudo isso for verdade, sugiro usar o basic_stringwho que char_typecorresponde ao tamanho do primitivo contido no seu vector. Você deve incluir um static_assertno seu código para validar que esses tamanhos permaneçam consistentes:
Essa solução pode ser um pouco complicada, mas boost-rangetambém tem outras coisas boas a oferecer.
#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;}
Muitas vezes, a intenção é combinar vetor ae biterar sobre ele, fazendo alguma operação. Nesse caso, existe a joinfunção simples ridícula .
#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 vetores grandes, isso pode ser uma vantagem, pois não há cópia. Também pode ser usado para copiar uma generalização facilmente para mais de um contêiner.
Por alguma razão, não há nada como boost::join(a,b,c), o que poderia ser razoável.
Para ser honesto, você pode concatenar rapidamente dois vetores copiando elementos de dois vetores para o outro ou apenas anexando apenas um dos dois vetores !. Depende do seu objetivo.
Método 1: Atribuir novo vetor com seu tamanho é a soma do tamanho de dois vetores originais.
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: anexar o vetor A adicionando / inserindo elementos do vetor 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());
O que sua resposta acrescenta que ainda não foi fornecida em outras respostas?
Mat
13
@ Mat: caracteres em negrito.
Marcv81
Se os vetores originais não forem mais necessários depois, pode ser melhor usá-los para std::move_iteratorque os elementos sejam movidos em vez de copiados. (consulte en.cppreference.com/w/cpp/iterator/move_iterator ).
tmlen 23/02
O que é setcapacity? O que é function: ?
LF
@ LF Acho que ele está falando sobre o resizemétodo.
a + b
oua.concat(b)
na biblioteca padrão? Talvez a implementação padrão não ser o melhor, mas cada concatenação de matriz não precisa ser micro-otimizadoRespostas:
fonte
reserve
o vetor de destino primeiro?vector1.capacity() >= 2 * vector1.size()
. O que é atípico, a menos que você tenha telefonadostd::vector::reserve()
. Caso contrário, o vector vai realocar, invalidar os iterators passados como parâmetros 2 e 3..concat
ou+=
algo parecidoSe você estiver usando o C ++ 11 e desejar mover os elementos, em vez de apenas copiá-los, poderá usar
std::move_iterator
junto com insert (ou copy):Isso não será mais eficiente para o exemplo com ints, pois movê-los não é mais eficiente do que copiá-los, mas para uma estrutura de dados com movimentos otimizados, ele pode evitar a cópia de um estado desnecessário:
Após a mudança, o elemento src é deixado em um estado indefinido, mas seguro para destruir, e seus elementos anteriores foram transferidos diretamente para o novo elemento do dest no final.
fonte
std::move(src.begin(), src.end(), back_inserter(dest))
?Eu usaria a função de inserção , algo como:
fonte
Ou você pode usar:
Esse padrão é útil se os dois vetores não contêm exatamente o mesmo tipo de coisa, porque você pode usar algo em vez de std :: back_inserter para converter de um tipo para outro.
fonte
reserve
primeiro. O motivostd::copy
às vezes é útil é se você deseja usar algo diferenteback_inserter
.Com o C ++ 11, prefiro seguir o anexo b a a:
quando
a
eb
não se sobrepõem eb
não será mais usado.Isto é
std::move
de<algorithm>
, não o habitualstd::move
de<utility>
.fonte
insert
caminho antigo , que é mais seguro.insert()
commove_iterator
s? Se sim, como?std::move
que estamos falando aqui, pois a maioria das pessoas não conhece essa sobrecarga. Espero que seja uma melhoria.fonte
Eu prefiro um que já é mencionado:
Mas se você usa C ++ 11, há mais uma maneira genérica:
Além disso, não faz parte de uma pergunta, mas é recomendável usá-lo
reserve
antes de anexá-lo para obter um melhor desempenho. E se você estiver concatenando o vetor consigo mesmo, sem reservar, ele falhará, então você sempre devereserve
.Então, basicamente, o que você precisa:
fonte
std::
é deduzido através da pesquisa dependente de argumento .end(a)
Será suficiente.std::
se o tipo de origema
vierstd
, o que anula o aspecto genérico.Com o intervalo v3 , você pode ter uma concatenação lenta :
Demo .
fonte
Você deve usar vector :: insert
fonte
Um aumento geral no desempenho para concatenar é verificar o tamanho dos vetores. E mesclar / inserir o menor com o maior.
fonte
v1.insert(v2.end()...
está a utilizar uma iteração parav2
a determinar a posição emv1
.Se você deseja concatenar vetores de forma concisa, pode sobrecarregar o
+=
operador.Então você pode chamar assim:
fonte
Se você estiver interessado em uma garantia forte de exceção (quando o construtor de cópias puder lançar uma exceção):
Similar
append_move
com garantia forte não pode ser implementado em geral se o construtor de movimento do elemento vetorial puder lançar (o que é improvável, mas ainda).fonte
v1.erase(...
jogar também?insert
já lida com isso. Além disso, essa chamada paraerase
é equivalente a aresize
.Adicione este ao seu arquivo de cabeçalho:
e use desta maneira:
r conterá [1,2,62]
fonte
Aqui está uma solução de uso geral usando a semântica de movimentação do C ++ 11:
Observe como isso difere de
append
ing para avector
.fonte
Você pode preparar seu próprio modelo para o operador +:
A próxima coisa - basta usar +:
Este exemplo fornece a saída:
fonte
T operator+(const T & a, const T & b)
é perigoso, é melhor usarvector<T> operator+(const vector<T> & a, const vector<T> & b)
.Existe um algoritmo
std::merge
do C ++ 17 , que é muito fácil de usar,Abaixo está o exemplo:
fonte
std::vector::insert
, mas faz algo diferente: mesclar dois intervalos em um novo intervalo versus inserir um vetor no final de outro. Vale mencionar na resposta?Se seu objetivo é simplesmente iterar o intervalo de valores para fins somente leitura, uma alternativa é agrupar os dois vetores em torno de um proxy (O (1)) em vez de copiá-los (O (n)), para que sejam vistos imediatamente como um único, contíguo.
Consulte https://stackoverflow.com/a/55838758/2379625 para obter mais detalhes, incluindo a implementação 'VecProxy', bem como prós e contras.
fonte
fonte
Eu implementei essa função que concatena qualquer número de contêineres, movendo-se de rvalue-reference e copiando de outra forma
fonte
Se o que você procura é uma maneira de anexar um vetor a outro após a criação,
vector::insert
é sua melhor aposta, como já foi respondido várias vezes, por exemplo:Infelizmente, não há como construir um
const vector<int>
, como acima você deve construir e depoisinsert
.Se o que você está realmente procurando é um contêiner para conter a concatenação desses dois
vector<int>
s, pode haver algo melhor disponível para você, se:vector
contém primitivasconst
contêinerSe tudo isso for verdade, sugiro usar o
basic_string
who quechar_type
corresponde ao tamanho do primitivo contido no seuvector
. Você deve incluir umstatic_assert
no seu código para validar que esses tamanhos permaneçam consistentes:Com isso, você pode apenas fazer:
Para obter mais informações sobre as diferenças entre
string
evector
você pode procurar aqui: https://stackoverflow.com/a/35558008/2642059Para um exemplo ao vivo deste código, você pode procurar aqui: http://ideone.com/7Iww3I
fonte
Essa solução pode ser um pouco complicada, mas
boost-range
também tem outras coisas boas a oferecer.Muitas vezes, a intenção é combinar vetor
a
eb
iterar sobre ele, fazendo alguma operação. Nesse caso, existe ajoin
função simples ridícula .Para vetores grandes, isso pode ser uma vantagem, pois não há cópia. Também pode ser usado para copiar uma generalização facilmente para mais de um contêiner.
Por alguma razão, não há nada como
boost::join(a,b,c)
, o que poderia ser razoável.fonte
Você pode fazer isso com algoritmos STL pré-implementados usando um modelo para um uso do tipo polimórfico.
Você pode limpar o segundo vetor se não quiser usá-lo mais (
clear()
método).fonte
Para ser honesto, você pode concatenar rapidamente dois vetores copiando elementos de dois vetores para o outro ou apenas anexando apenas um dos dois vetores !. Depende do seu objetivo.
Método 1: Atribuir novo vetor com seu tamanho é a soma do tamanho de dois vetores originais.
Método 2: anexar o vetor A adicionando / inserindo elementos do vetor B.
fonte
std::move_iterator
que os elementos sejam movidos em vez de copiados. (consulte en.cppreference.com/w/cpp/iterator/move_iterator ).setcapacity
? O que éfunction:
?resize
método.