Лучший способ извлечь субвектор из вектора?
Предположим, у меня есть std::vector (назовем его myVec) в размере N. Каков самый простой способ построить новый вектор, состоящий из копии элементов X через Y, где 0 myVec [100000] через myVec [100999] в векторе размере 150000.
если это не может быть сделано эффективно с вектором, есть ли другой тип данных STL, который я должен использовать вместо этого?
13 ответов:
vector<T>::const_iterator first = myVec.begin() + 100000; vector<T>::const_iterator last = myVec.begin() + 101000; vector<T> newVec(first, last);это операция O(N) для построения нового вектора, но на самом деле нет лучшего способа.
просто используйте векторный конструктор.
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), в вашем случаеfoo = std::vector(myVec.begin () + 100000, myVec.begin () + 150000);см., например,здесь
если оба не будут изменены (нет добавления / удаления элементов-изменение существующих из них нормально, пока вы обращаете внимание на проблемы с потоками), вы можете просто передать
data.begin() + 100000иdata.begin() + 101000, и делать вид, что ониbegin()иend()меньшего вектора.или, поскольку векторное хранилище гарантированно будет непрерывным, вы можете просто передать массив из 1000 элементов:
T *arrayOfT = &data[0] + 100000; size_t arrayOfTLength = 1000;оба эти метода занимают постоянное время, но требуют, чтобы длина данные не увеличиваются, вызывая перераспределение.
вы не упомянули что типа
std::vector<...> myVecесть, но если это простой тип или структура/класс, который не включает указатели, и вы хотите получить максимальную эффективность, то вы можете сделать прямую копию памяти (которая, я думаю, будет быстрее, чем другие ответы). Вот общий примерstd::vector<type> myVecздесьtypeв данном случае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
в эти дни, мы используем
spans! Так вы бы написали:#include <gsl/span> ... auto start_pos = 100000; auto length = 1000; auto my_subspan = gsl::make_span(myvec).subspan(start_pos, length);чтобы получить диапазон 1000 элементов того же типа, что и
myvec'ы. Теперь это не копия, это просто вид данных в векторе, так что будьте осторожны. Если вам нужна фактическая копия, вы можете сделать:std::vector<T> new_vec(my_subspan.begin(), my_subspan.end());Примечания:
- С C++20 вы бы использовали
std::spanи#include <span>, а не#include <gsl/span>.- для получения дополнительной информации о пролетах см.:что "пядь" и когда я должен использовать один?
можно использовать STL copy с производительностью O(M), когда M-размер подвектора.
единственный способ спроецировать коллекцию, которая не является линейным временем, - это сделать это лениво, где результирующий "вектор" фактически является подтипом, который делегирует исходную коллекцию. Например, в Scala
List#subseqметод создать подпоследовательность в постоянное время. Однако это работает только в том случае, если коллекция является неизменяемой и если базовый язык поддерживает сборку мусора.
ОК. Это довольно старая дискуссия. Но я только что обнаружил кое что:
slice_array - может ли это быть быстрой альтернативой ? Я его не проверял.
отправляю это только для других..Держу пари, что первый кодер уже готов. Для простых типов данных никакая копия не требуется, просто вернитесь к старым добрым методам кода C.
передать указатель p и лен ни к чему, нуждающихся в наращивает.std::vector <int> myVec; int *p; // Add some data here and set start, then p=myVec.data()+start;нотелен должен быть!!
len < myVec.size()-start
может быть array_view / span в библиотеке GSL-это хороший вариант.
вот также реализация одного файла:array_view.
копирование элементов из одного вектора в другой легко
В этом примере я использую вектор пар, чтобы сделать его легко понять
-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)]'
Как вы можете видеть, вы можете легко копировать элементы из одного вектора в другой, если вы хотите скопировать элементы из индекса 10 в 16 например, то мы будем использоватьvector<pair<int, int> > a(v.begin()+10, v.begin+16);и если вы хотите элементы из индекса 10 в какой-то индекс от конца, то в этом случае
vector<pair<int, int> > a(v.begin()+10, v.end()-5);Надежда это помогает, просто помните в последнем случае
v.end()-5 > v.begin()+10
еще один вариант: Полезно, например при перемещении между
thrust::device_vectorиthrust::host_vector, когда вы не можете использовать конструктор.std::vector<T> newVector; newVector.reserve(1000); std::copy_n(&vec[100000], 1000, std::back_inserter(newVector));также должна быть сложность O (N)
вы можете объединить это с top anwer code
vector<T>::const_iterator first = myVec.begin() + 100000; vector<T>::const_iterator last = myVec.begin() + 101000; std::copy(first, last, std::back_inserter(newVector));
Comments