web-dev-qa-db-fra.com

Le meilleur moyen d'extraire un sous-vecteur d'un vecteur?

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?

227
An̲̳̳drew
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.

293
Greg Rogers

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]);
69
Martin York

std::vector(input_iterator, input_iterator), dans votre cas foo = std::vector(myVec.begin () + 100000, myVec.begin () + 150000);, voir par exemple ici

23
Anteru

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.

10
Eclipse

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> myVectype 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
6
MasterHD

Ces jours-ci, nous utilisons spans! 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:

6
einpoklum

Vous pouvez utiliser STL copy avec la performance O(M) lorsque M est la taille du sous-vecteur.

3
Yuval F

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é.

1
umayfindurself

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.

1
Daniel Spiewak

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));
0
JHBonarius

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 .

0
myd7349

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

0
Jishu Dohare

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

0
mrrgu