Лучший способ извлечь субвектор из вектора?



Предположим, у меня есть std::vector (назовем его myVec) в размере N. Каков самый простой способ построить новый вектор, состоящий из копии элементов X через Y, где 0 myVec [100000] через myVec [100999] в векторе размере 150000.



если это не может быть сделано эффективно с вектором, есть ли другой тип данных STL, который я должен использовать вместо этого?

797   13  

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());

Примечания:

можно использовать STL copy с производительностью O(M), когда M-размер подвектора.

единственный способ спроецировать коллекцию, которая не является линейным временем, - это сделать это лениво, где результирующий "вектор" фактически является подтипом, который делегирует исходную коллекцию. Например, в Scala List#subseq метод создать подпоследовательность в постоянное время. Однако это работает только в том случае, если коллекция является неизменяемой и если базовый язык поддерживает сборку мусора.

ОК. Это довольно старая дискуссия. Но я только что обнаружил кое что:

slice_array - может ли это быть быстрой альтернативой ? Я его не проверял.

отправляю это только для других..Держу пари, что первый кодер уже готов. Для простых типов данных никакая копия не требуется, просто вернитесь к старым добрым методам кода C.

std::vector <int>   myVec;
int *p;
// Add some data here and set start, then
p=myVec.data()+start;
передать указатель p и лен ни к чему, нуждающихся в наращивает.

нотелен должен быть!! 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

    Ничего не найдено.