unir - que es un arreglo en c++
Concatenando dos std:: vectores (17)
¿Cómo concatenar dos std::vector
s?
Agregue este a su archivo de cabecera:
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;
}
y utilízalo de esta manera:
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 contendrá [1,2,62]
Aquí hay una solución de propósito general que usa C ++ 11 mover semántica:
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);
}
Observe cómo esto difiere de append
a un vector
.
Debes usar vector::insert
v1.insert(v1.end(), v2.begin(), v2.end());
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 puedes usar algo en lugar de std :: back_inserter para convertir de un tipo a otro.
Para ser honesto, puedes concatenar rápidamente dos vectores copiando elementos de dos vectores en el otro o simplemente agregar uno de los dos vectores. Depende de tu punteria.
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());
Prefiero uno que ya está mencionado:
a.insert(a.end(), b.begin(), b.end());
Pero si usas C ++ 11, hay una forma más genérica:
a.insert(std::end(a), std::begin(b), std::end(b));
Además, no es parte de una pregunta, pero es recomendable utilizar la reserve
antes de agregar para un mejor rendimiento. Y si está concatenando el vector consigo mismo, sin reservar falla, por lo que siempre debe reserve
.
Así que básicamente lo que necesitas:
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());
}
Puedes preparar tu propia plantilla para el operador +:
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;
}
Lo siguiente - solo usa +:
vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
cout << x << " ";
cout << endl;
Este ejemplo da salida:
1 2 3 4 5 6 7 8
Si está interesado en una fuerte garantía de excepción (cuando el constructor de copias puede lanzar una excepción):
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;
}
}
Un append_move
similar con una fuerte garantía no se puede implementar en general si el constructor de movimientos del elemento vector puede lanzar (lo cual es poco probable pero aún así).
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 la inserción (o copia):
#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;
}
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 <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;
}
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.
Si lo que está buscando es una manera 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<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>
, ya que anteriormente debe construir y luego insert
.
Si lo que realmente está buscando es un contenedor para contener la concatenación de estos dos vector<int>
, puede haber algo mejor disponible para usted, si:
- Tu
vector
contiene primitivas. - Sus primitivas contenidas son de tamaño de 32 bits o más pequeñas
- Quieres un contenedor de
const
Si todo lo anterior es cierto, sugeriría usar la basic_string
cuyo tipo de char_type
coincide con el tamaño de la primitiva contenida en tu vector
. Debe incluir un static_assert
en su código para validar que estos tamaños sean consistentes:
static_assert(sizeof(char32_t) == sizeof(int));
Con esta afirmación verdadera solo puedes hacer:
const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());
Para obtener más información sobre las diferencias entre la string
y el vector
, puede consultar aquí: https://.com/a/35558008/2642059
Para ver un ejemplo en vivo de este código, puede consultar aquí: http://ideone.com/7Iww3I
Un aumento de rendimiento general para concatenar es verificar el tamaño de los vectores. Y fusionar / insertar el más pequeño con el más grande.
//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());
}
Yo usaría la función de inserción , algo como:
vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
std::vector<int> first;
std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );