Supposons que j'ai un std::vector
(appelons-le myVec
) de taille N
. Quel est le moyen le plus simple de construire un nouveau vecteur consistant en une copie des éléments X à Y, où 0 <= X <= Y <= N-1? Par exemple, myVec [100000]
à myVec [100999]
dans un vecteur de taille 150000
.
Si cela ne peut pas être fait efficacement avec un vecteur, y a-t-il un autre type de données STL que je devrais utiliser à la place?
vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
vector<T> newVec(first, last);
C'est une opération O(N) de construire le nouveau vecteur, mais il n'y a pas vraiment de meilleur moyen.
Il suffit d'utiliser le constructeur de vecteur.
std::vector<int> data();
// Load Z elements into data so that Z > Y > X
std::vector<int> sub(&data[100000],&data[101000]);
std::vector(input_iterator, input_iterator)
, dans votre cas foo = std::vector(myVec.begin () + 100000, myVec.begin () + 150000);
, voir par exemple ici
Si les deux ne vont pas être modifiés (pas d'ajout/suppression d'éléments (il est correct de modifier des éléments existants tant que vous tenez compte des problèmes de thread)), vous pouvez simplement faire passer data.begin() + 100000
et data.begin() + 101000
et prétendre qu'ils sont les begin()
et end()
un vecteur plus petit.
Ou, étant donné que le stockage de vecteurs est garanti pour être contigu, vous pouvez simplement faire passer un tableau de 1000 éléments:
T *arrayOfT = &data[0] + 100000;
size_t arrayOfTLength = 1000;
Ces deux techniques prennent un temps constant, mais nécessitent que la longueur des données n'augmente pas, ce qui déclenche une réallocation.
Vous n'avez pas mentionné le type std::vector<...> myVec
, mais s'il s'agit d'un type simple ou d'une structure/classe qui n'inclut pas les pointeurs et que vous souhaitez une efficacité optimale, vous pouvez créer une copie directe en mémoire les autres réponses fournies). Voici un exemple général pour std::vector<type> myVec
où type
dans ce cas est int
:
typedef int type; //choose your custom type/struct/class
int iFirst = 100000; //first index to copy
int iLast = 101000; //last index + 1
int iLen = iLast - iFirst;
std::vector<type> newVec;
newVec.resize(iLen); //pre-allocate the space needed to write the data directly
memcpy(&newVec[0], &myVec[iFirst], iLen*sizeof(type)); //write directly to destination buffer from source buffer
Ces jours-ci, nous utilisons span
s! Donc, vous écririez:
#include <gsl/span>
...
auto start_pos = 100000;
auto length = 1000;
auto my_subspan = gsl::make_span(myvec).subspan(start_pos, length);
pour obtenir une étendue de 1000 éléments du même type que ceux de myvec
. Maintenant, il s'agit de pas une copie, c'est juste une vue des données dans le vecteur, alors soyez prudent. Si vous voulez une copie réelle, vous pouvez faire:
std::vector<T> new_vec(my_subspan.begin(), my_subspan.end());
Remarques:
std::span
et #include <span>
plutôt que #include <gsl/span>
.Vous pouvez utiliser STL copy avec la performance O(M) lorsque M est la taille du sous-vecteur.
D'accord. C'est une jolie vieille discussion. Mais je viens de découvrir quelque chose d'intéressant:
slice_array - Cela pourrait-il être une alternative rapide? Je ne l'ai pas testé.
La seule façon de projeter une collection qui n'est pas linéaire est de le faire paresseusement, le "vecteur" résultant étant en fait un sous-type qui délègue à la collection d'origine. Par exemple, la méthode List#subseq
de Scala crée une sous-séquence en temps constant. Toutefois, cela ne fonctionne que si la collecte est immuable et si le langage sous-jacent utilise la récupération de place.
Encore une autre option: Utile par exemple pour passer d'un thrust::device_vector
à un thrust::Host_vector
, où vous ne pouvez pas utiliser le constructeur.
std::vector<T> newVector;
newVector.reserve(1000);
std::copy_n(&vec[100000], 1000, std::back_inserter(newVector));
Devrait également être la complexité O (N)
Vous pouvez combiner cela avec le meilleur code de réponse
vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
std::copy(first, last, std::back_inserter(newVector));
Peut-être que array_view/span dans la bibliothèque GSL est une bonne option.
Voici également une implémentation de fichier unique: array_view .
Vous pouvez simplement utiliser insert
vector<type> myVec { n_elements };
vector<type> newVec;
newVec.insert(newVec.begin(), myVec.begin() + X, myVec.begin() + Y);
Copiez facilement des éléments d’un vecteur à un autre
Dans cet exemple, j’utilise un vecteur de paires pour le rendre facile à comprendre
`
vector<pair<int, int> > v(n);
//we want half of elements in vector a and another half in vector b
vector<pair<lli, lli> > a(v.begin(),v.begin()+n/2);
vector<pair<lli, lli> > b(v.begin()+n/2, v.end());
//if v = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
//then a = [(1, 2), (2, 3)]
//and b = [(3, 4), (4, 5), (5, 6)]
//if v = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]
//then a = [(1, 2), (2, 3), (3, 4)]
//and b = [(4, 5), (5, 6), (6, 7)]
'
Comme vous pouvez le constater, vous pouvez facilement copier des éléments d’un vecteur à un autre. Par exemple, si vous souhaitez copier des éléments de l’indice 10 à 16, nous utiliserons:
vector<pair<int, int> > a(v.begin()+10, v.begin+16);
et si vous voulez des éléments de l'index 10 à un index de la fin, alors dans ce cas
vector<pair<int, int> > a(v.begin()+10, v.end()-5);
espérons que cela vous aidera, rappelez-vous que dans le dernier cas, v.end()-5 > v.begin()+10
Afficher ce retard juste pour les autres..Je parie que le premier codeur est déjà terminé. Pour les types de données simples, aucune copie n'est nécessaire, il suffit de revenir aux bonnes vieilles méthodes de code C.
std::vector <int> myVec;
int *p;
// Add some data here and set start, then
p=myVec.data()+start;
Puis passez le pointeur p et un len à tout ce qui nécessite un sous-vecteur.
notelen doit être !! len < myVec.size()-start