web-dev-qa-db-de.com

Bester Weg, einen Subvector aus einem Vektor zu extrahieren?

Angenommen, ich habe einen std::vector (nennen wir es myVec) der Größe N. Was ist der einfachste Weg, einen neuen Vektor zu konstruieren, der aus einer Kopie der Elemente X bis Y besteht, wobei 0 <= X <= Y <= N-1 ist? Zum Beispiel myVec [100000] bis myVec [100999] in einem Vektor der Größe 150000.

Wenn dies mit einem Vektor nicht effizient durchgeführt werden kann, sollte ich dann einen anderen STL-Datentyp verwenden?

227
An̲̳̳drew
vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
vector<T> newVec(first, last);

Es ist eine O(N) -Operation, um den neuen Vektor zu konstruieren, aber es gibt keinen wirklich besseren Weg.

293
Greg Rogers

Verwenden Sie einfach den Vektorkonstruktor.

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), in Ihrem Fall foo = std::vector(myVec.begin () + 100000, myVec.begin () + 150000);, siehe zum Beispiel hier

23
Anteru

Wenn beide nicht geändert werden (kein Hinzufügen/Löschen von Elementen - das Ändern vorhandener Elemente ist in Ordnung, solange Sie die Thread-Probleme beachten), können Sie data.begin() + 100000 und data.begin() + 101000 einfach weitergeben und so tun, als wären sie begin() und end() von ein kleinerer Vektor.

Da der Vektorspeicher garantiert zusammenhängend ist, können Sie einfach ein Array mit 1000 Elementen übergeben: 

T *arrayOfT = &data[0] + 100000;
size_t arrayOfTLength = 1000;

Beide Techniken benötigen eine konstante Zeit, erfordern jedoch, dass die Länge der Daten nicht zunimmt, was eine Neuzuordnung auslöst.

10
Eclipse

Sie haben nicht erwähnt, welcher Typ std::vector<...> myVec ist, aber wenn es sich um einen einfachen Typ oder eine einfache Struktur/Klasse handelt, die keine Zeiger enthält, und Sie die beste Effizienz wünschen, können Sie eine direkte Speicherkopie erstellen (die meiner Meinung nach schneller ist als die anderen Antworten zur Verfügung gestellt). Hier ist ein allgemeines Beispiel für std::vector<type> myVec, wobei type in diesem Fall int ist:

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

In diesen Tagen verwenden wir spans! So würden Sie schreiben:

#include <gsl/span>

...
auto start_pos = 100000;
auto length = 1000;
auto my_subspan = gsl::make_span(myvec).subspan(start_pos, length);

um eine Spanne von 1000 Elementen desselben Typs wie myvec zu erhalten. Nun, dies ist keine Kopie, es ist nur eine Ansicht der Daten im Vektor, seien Sie also vorsichtig. Wenn Sie eine tatsächliche Kopie wünschen, können Sie Folgendes tun:

std::vector<T> new_vec(my_subspan.begin(), my_subspan.end());

Anmerkungen:

6
einpoklum

Sie können STL copy mit O(M) Performance verwenden, wenn M die Größe des Subvektors hat.

3
Yuval F

OK. Dies ist eine ziemlich alte Diskussion. Aber ich habe gerade etwas Schönes entdeckt:

slice_array - Könnte dies eine schnelle Alternative sein? Ich habe es nicht getestet.

1
umayfindurself

Die einzige Möglichkeit, eine Sammlung ohne lineare Zeit zu projizieren, besteht darin, dies nur langsam zu tun, wobei der resultierende "Vektor" tatsächlich ein Untertyp ist, der an die ursprüngliche Sammlung delegiert. Beispielsweise erstellt die List#subseq-Methode von Scala eine Subsequenz in konstanter Zeit. Dies funktioniert jedoch nur, wenn die Sammlung unveränderlich ist und die zugrunde liegende Sprache über eine Müllsammlung verfügt.

1
Daniel Spiewak

Noch eine weitere Option: Nützlich zum Beispiel, wenn Sie zwischen einem thrust::device_vector und einem thrust::Host_vector wechseln, wo Sie den Konstruktor nicht verwenden können.

std::vector<T> newVector;
newVector.reserve(1000);
std::copy_n(&vec[100000], 1000, std::back_inserter(newVector));

Sollte auch die Komplexität O (N) sein

Sie können dies mit einem Top-Antwortcode kombinieren

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

Vielleicht ist das array_view/span in der GSL-Bibliothek eine gute Option.

Hier ist auch eine einzelne Dateiimplementierung: array_view .

0
myd7349

Sie könnten einfach insert verwenden

vector<type> myVec { n_elements };

vector<type> newVec;

newVec.insert(newVec.begin(), myVec.begin() + X, myVec.begin() + Y);

Elemente einfach von einem Vektor in einen anderen kopieren
In diesem Beispiel verwende ich einen Vektor von Paaren, um es leicht verständlich zu machen.
`

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)]

'
Wie Sie sehen, können Sie Elemente einfach von einem Vektor in einen anderen kopieren. Wenn Sie beispielsweise Elemente aus Index 10 bis 16 kopieren möchten, würden wir dies verwenden

vector<pair<int, int> > a(v.begin()+10, v.begin+16);

und wenn Sie Elemente von Index 10 bis zu einem Index von Ende möchten, dann in diesem Fall

vector<pair<int, int> > a(v.begin()+10, v.end()-5);

ich hoffe, das hilft, erinnere dich einfach an den letzten Fall v.end()-5 > v.begin()+10

0
Jishu Dohare

Ich wette, der erste Coder ist jetzt fertig. Für einfache Datentypen wird keine Kopie benötigt, sondern es wird auf gute alte C-Codemethoden zurückgegriffen.

std::vector <int>   myVec;
int *p;
// Add some data here and set start, then
p=myVec.data()+start;

Übergeben Sie dann den Zeiger p und a len an alle Objekte, die einen Subvektor benötigen.

muss notelen sein !! len < myVec.size()-start

0
mrrgu