Comment obtenir un certain élément dans une liste, compte tenu de la position?

92

J'ai donc une liste:

list<Object> myList;
myList.push_back(Object myObject);

Je ne suis pas sûr mais je suis convaincu que ce serait le "0ème" élément du tableau. Y a-t-il une fonction que je peux utiliser qui renverra "myObject"?

Object copy = myList.find_element(0);

?

Tester
la source
8
Il n'y a pas de tableau - c'est une liste. Si vous souhaitez indexer par nombre entier, pourquoi ne pas utiliser à la vectorplace?
Paul
2
Si vous voulez toujours l'élément 0, utilisez front().
Paul
Je n'ai pas testé cela, mais je suppose que myList.front () + num fonctionnerait ici
Serguei Fedorov
2
@SergueiFedorov: non, ce n'est pas le cas
Algoman

Réponses:

129

Si vous avez fréquemment besoin d'accéder au Nième élément d'une séquence, std::listqui est implémenté sous la forme d'une liste doublement chaînée, n'est probablement pas le bon choix. std::vectorou std::dequeserait probablement mieux.

Cela dit, vous pouvez obtenir un itérateur vers le Nième élément en utilisant std::advance:

std::list<Object> l;
// add elements to list 'l'...

unsigned N = /* index of the element you want to retrieve */;
if (l.size() > N)
{
    std::list<Object>::iterator it = l.begin();
    std::advance(it, N);
    // 'it' points to the element at index 'N'
}

Pour un conteneur qui ne fournit pas d'accès aléatoire, comme std::list, std::advanceappelle operator++les Nheures d' itérateur . Sinon, si votre implémentation de bibliothèque standard le fournit, vous pouvez appeler std::next:

if (l.size() > N)
{
    std::list<Object>::iterator it = std::next(l.begin(), N);
}

std::nextis encapsule efficacement un appel à std::advance, ce qui facilite l'avance d'un itérateur Navec moins de lignes de code et moins de variables mutables. std::nexta été ajouté dans C ++ 11.

James McNellis
la source
18
Alors que vous payez une pénalité de performance en recherchant une liste chaînée en raison du manque d'accès aléatoire, vous payez une pénalité de performance beaucoup plus importante si vous devez insérer ou supprimer des données au milieu d'un vecteur ou d'un deque. La question ne contient pas en fait suffisamment d'informations pour décider s'ils utilisent le conteneur idéal à leurs fins.
tloach le
1
Il est à noter que lors de l'utilisation de std::advanceou std::next, il est facile d'appeler UB. Il n'y a pas de vérification des limites.
okovko
33

std::listne fournit aucune fonction pour obtenir un élément avec un index. Vous pouvez essayer de l'obtenir en écrivant du code, ce que je ne recommanderais pas, car ce serait inefficace si vous devez le faire fréquemment.

Qu'est - ce que vous avez besoin est: std::vector. Utilisez-le comme:

std::vector<Object> objects;
objects.push_back(myObject);

Object const & x = objects[0];    //index isn't checked
Object const & y = objects.at(0); //index is checked 
Nawaz
la source
7
std::list<Object> l; 
std::list<Object>::iterator ptr;
int i;

for( i = 0 , ptr = l.begin() ; i < N && ptr != l.end() ; i++ , ptr++ );

if( ptr == l.end() ) {
    // list too short  
} else {
    // 'ptr' points to N-th element of list
}
furas
la source
3

Peut-être pas le moyen le plus efficace. Mais vous pouvez convertir la liste en vecteur.

#include <list>
#include <vector>

list<Object> myList;

vector<Object> myVector(myList.begin(), myList.end());

Accédez ensuite au vecteur à l'aide de l'opérateur [x].

auto x = MyVector[0];

Vous pouvez mettre cela dans une fonction d'assistance:

#include <memory>
#include <vector>
#include <list>

template<class T>
shared_ptr<vector<T>> 
ListToVector(list<T> List) {
shared_ptr<vector<T>> Vector {
        new vector<string>(List.begin(), List.end()) }
return Vector;
}

Ensuite, utilisez la fonction d'assistance comme ceci:

auto MyVector = ListToVector(Object);
auto x = MyVector[0];
Bill Moore
la source