Нарезка вектора
У меня есть std::vector. Я хочу создать итераторы, представляющие срез этого вектора. Как мне это сделать? В псевдо С++:
class InterestingType;
void doSomething(slice& s) {
for (slice::iterator i = s.begin(); i != s.end(); ++i) {
std::cout << *i << endl;
}
}
int main() {
std::vector v();
for (int i= 0; i < 10; ++i) { v.push_back(i); }
slice slice1 = slice(v, 1, 5);
slice slice2 = slice(v, 2, 4);
doSomething(slice1);
doSomething(slice2);
return 0;
}
Я бы предпочел не копировать элементы в новую структуру данных.
Ответы
Ответ 1
Вы просто используете пару итераторов:
typedef std::vector<int>::iterator vec_iter;
void doSomething(vec_iter first, vec_iter last) {
for (vec_iter cur = first; cur != last; ++cur) {
std::cout << *cur << endl;
}
}
int main() {
std::vector v();
for (int i= 0; i < 10; ++i) { v.push_back(i); }
doSomething(v.begin() + 1, v.begin() + 5);
doSomething(v.begin() + 2, v.begin() + 4);
return 0;
}
В качестве альтернативы библиотека Boost.Range должна позволять вам представлять пары итераторов как один объект, но выше это канонический способ сделать это.
Ответ 2
Я изучил Python, прежде чем научился С++. Я задавался вопросом, предложил ли С++ срез векторов, таких как нарезка в списках Python. Потребовалось пару минут, чтобы написать эту функцию, которая позволяет срезать вектор, аналогичный тому, как это делается на Python.
vector<int> slice(const vector<int>& v, int start=0, int end=-1) {
int oldlen = v.size();
int newlen;
if (end == -1 or end >= oldlen){
newlen = oldlen-start;
} else {
newlen = end-start;
}
vector<int> nv(newlen);
for (int i=0; i<newlen; i++) {
nv[i] = v[start+i];
}
return nv;
}
Использование:
vector<int> newvector = slice(vector_variable, start_index, end_index);
Элемент start_index будет включен в срез, тогда как end_index не будет включен.
Пример:
Для вектора v1, как {1,3,5,7,9}
slice (v1,2,4) возвращает {5,7}
Ответ 3
Взято из здесь:
std::vector<myvector::value_type>(myvector.begin()+start, myvector.begin()+end).swap(myvector);
Ответ 4
Как говорили другие, вы можете представить "срез" как пару итераторов. Если вы хотите использовать Boost, вы можете использовать концепцию диапазона. Тогда вы будете иметь даже функции begin()/end(), доступные, и вся эта вещь выглядит как контейнер.
Ответ 5
использовать адаптеры диапазона усиления. они lazy:
operator |() используется для ленивого добавления нового поведения и никогда не изменяет его левый аргумент.
boost::for_each(v|sliced(1,5)|transformed(doSomething));
doSomething
должен принимать диапазон ввода. простая (может быть lambda) обертка будет исправлять это.
Ответ 6
Вы можете представить эти "срезы" с парой итераторов.