Supposons que j'ai une std::vector
(appelons-la myVec
) de taille N
. Quelle est la façon la plus simple de construire un nouveau vecteur composé d'une copie des éléments X à Y, où 0 <= X <= Y <= N-1? Par exemple, myVec [100000]
grâce à myVec [100999]
un vecteur de taille 150000
.
Si cela ne peut pas être fait efficacement avec un vecteur, existe-t-il un autre type de données STL que je devrais utiliser à la place?
Réponses:
C'est une opération O (N) pour construire le nouveau vecteur, mais il n'y a pas vraiment de meilleure façon.
la source
O(Y-X)
, ou nous dirionsO(Z) where Z=Y-X
.vector<T> newVec(myVec.begin() + 100000, myVec.begin() + 101000);
?Utilisez simplement le constructeur vectoriel.
la source
operator[]
renvoie une référence. Ce n'est qu'au point où vous lisez ou écrivez la référence que cela deviendrait une violation d'accès. Puisque nous ne faisons ni l'un ni l'autre mais obtenons l'adresse, nous n'avons pas invoqué UB ,.std::vector<T>(input_iterator, input_iterator)
, dans votre casfoo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);
, voir par exemple icila source
De nos jours, nous utilisons
span
s! Vous écririez donc:pour obtenir une plage de 1000 éléments du même type que ceux
myvec
de. Ou une forme plus concise:(mais je n'aime pas autant cela, car la signification de chaque argument numérique n'est pas entièrement claire; et cela empire si la longueur et start_pos sont du même ordre de grandeur.)
Quoi qu'il en soit, n'oubliez pas que ce n'est 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:
Remarques:
gsl
signifie Guidelines Support Library. Pour plus d'informations surgsl
, voir: http://www.modernescpp.com/index.php/c-core-guideline-the-guidelines-support-library .gsl
, voir: https://github.com/Microsoft/GSLspan
. Vous utiliseriezstd::span
et#include <span>
plutôt que#include <gsl/span>
.std::vector
a un gazillion de constructeurs, il est super facile de tomber dans un que vous n'aviez pas l'intention d'utiliser, alors soyez prudent.la source
cbegin
etcend
juste pour le principe;)std::cbegin
etc même.Si les deux ne vont pas être modifiés (pas d'ajout / suppression d'éléments - la modification des éléments existants est très bien tant que vous tenez compte des problèmes de thread), vous pouvez simplement contourner
data.begin() + 100000
etdata.begin() + 101000
, et prétendre qu'ils sont lebegin()
etend()
d'un vecteur plus petit.Ou, comme le stockage vectoriel est garanti contigu, vous pouvez simplement contourner un tableau de 1000 éléments:
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.
la source
Cette discussion est assez ancienne, mais la plus simple n'est pas encore mentionnée, avec initialisation de liste :
Il nécessite c ++ 11 ou supérieur.
Exemple d'utilisation:
Résultat:
la source
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 de pointeurs et que vous voulez la meilleure efficacité, vous pouvez faire une copie de mémoire directe (qui, je pense, sera plus rapide que la autres réponses fournies). Voici un exemple général de l'std::vector<type> myVec
endroit où se trouvetype
dans ce casint
:la source
std::vector(myVec.begin () + 100000, myVec.begin () + 150000);
, la version plus longue de ce produit ne produirait-elle pas exactement le même assemblage?std::vector<>(iter, iter)
àmemmove()
, le cas échéant (si le constructeur est trivial, pour une définition appropriée de trivial).memcpy
. Faites unstd::copy
constructeur ou un constructeur qui accepte une plage (deux itérateurs), et le compilateur et std.library conspireront pour appelermemcpy
lorsque cela sera approprié.Vous pouvez simplement utiliser
insert
la source
Vous pouvez utiliser la copie STL avec des performances O (M) lorsque M est la taille du sous-vecteur.
la source
newvec.reserve(10100 - 10000);
. Les TI sont définitivement une option et techniquement, cela fonctionnera. Mais sur les deux, qu'allez-vous recommander?La seule façon de projeter une collection qui n'est pas du temps linéaire est de le faire paresseusement, où le "vecteur" résultant est en fait un sous-type qui délègue à la collection d'origine. Par exemple, la
List#subseq
méthode de Scala crée une sous-séquence en temps constant. Cependant, cela ne fonctionne que si la collection est immuable et si la langue sous-jacente est garbage collection.la source
Publier ce retard juste pour les autres ... Je parie que le premier codeur est terminé maintenant. 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.
Passez ensuite le pointeur p et un len à tout ce qui nécessite un sous-vecteur.
notelen doit être !!
len < myVec.size()-start
la source
Peut-être que array_view / span dans la bibliothèque GSL est une bonne option.
Voici également une implémentation d'un seul fichier: array_view .
la source
Copier facilement des éléments d'un vecteur à un autre
Dans cet exemple, j'utilise un vecteur de paires pour le rendre facile à comprendre
`
'
Comme vous pouvez le voir, vous pouvez facilement copier des éléments d'un vecteur à un autre, si vous souhaitez copier des éléments de l'index 10 à 16 par exemple, nous utiliserions
et si vous voulez des éléments de l'index 10 vers un index de la fin, alors dans ce cas
j'espère que cela aide, rappelez-vous juste dans le dernier cas
v.end()-5 > v.begin()+10
la source
Encore une autre option: utile par exemple lors du déplacement entre a
thrust::device_vector
et athrust::host_vector
, où vous ne pouvez pas utiliser le constructeur.Doit également être la complexité O (N)
Vous pouvez combiner cela avec le code de réponse supérieur
la source