web-dev-qa-db-fra.com

Découpage d'un vecteur

J'ai un std :: vector. Je veux créer des itérateurs représentant une tranche de ce vecteur. Comment fait-on ça? En pseudo C++:

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;
}

Je préférerais ne pas avoir à copier les éléments dans une nouvelle structure de données.

30
No Name

Vous utiliseriez simplement une paire d'itérateurs:

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;
}

Alternativement, la bibliothèque Boost.Range devrait vous permettre de représenter les paires d'itérateurs comme un seul objet, mais ce qui précède est la manière canonique de le faire.

28
jalf

J'ai appris Python avant d'apprendre C++. Je me demandais si C++ offrait le découpage de vecteurs comme le découpage dans les listes Python. Il a fallu quelques minutes pour écrire cette fonction qui vous permet de découper un vecteur analogue à la façon dont cela se fait en 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;
}

Usage:

vector<int> newvector = slice(vector_variable, start_index, end_index);

L'élément start_index sera inclus dans la tranche, tandis que le end_index ne sera pas inclus.

Exemple:

Pour un vecteur v1 comme {1,3,5,7,9}

slice (v1,2,4) renvoie {5,7}

9
Pranjal Mittal

Extrait de ici :

std::vector<myvector::value_type>(myvector.begin()+start, myvector.begin()+end).swap(myvector);

Exemple d'utilisation:

#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> indexes{3, 6, 9};

    for( auto index : indexes )
    {
        int slice = 3;
        std::vector<int> bar{1, 2, 3, 4, 5, 6, 7, 8, 9};
        std::vector<int>( bar.begin() + index - slice, bar.begin() + index ).swap(bar);

        std::cout << "bar index " << index << " contains:";
        for (unsigned i=0; i<bar.size(); i++)
            std::cout << ' ' << bar[i];
        std::cout << '\n';
    }

    return 0;
}

Les sorties:

bar index 3 contains: 1 2 3
bar index 6 contains: 4 5 6
bar index 9 contains: 7 8 9
5
jdehesa

Vous pouvez représenter ces "tranches" avec une paire d'itérateurs.

2
Artur Soler

utilisez des adaptateurs de gamme boost. ils sont paresseux :

l'opérateur | () est utilisé pour ajouter un nouveau comportement paresseusement et ne modifie jamais son argument gauche.

boost::for_each(v|sliced(1,5)|transformed(doSomething));

doSomething doit prendre la plage en entrée. un simple wrapper (peut-être lambda) résoudrait cela.

2
kirill_igum

Comme d'autres l'ont dit, vous pouvez représenter la "tranche" comme une paire d'itérateurs. Si vous souhaitez utiliser Boost, vous pouvez utiliser le concept de plage. Ensuite, vous aurez même des fonctions membres begin ()/end () disponibles et le tout ressemble beaucoup à un conteneur.

2
wilx