Come ottenere un determinato elemento in una lista, data la posizione?


92

Quindi ho una lista:

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

Non sono sicuro ma sono sicuro che questo sarebbe l'elemento "0" nell'array. C'è qualche funzione che posso usare che restituirà "mioOggetto"?

Object copy = myList.find_element(0);

?


8
Non esiste un array: è un elenco. Se vuoi indicizzare per numero intero, perché non usi vectorinvece?
Paul J. Lucas

2
Se vuoi sempre l'elemento 0, usa front().
Paul J. Lucas

Non l'ho testato, ma presumo che myList.front () + num funzionerebbe qui
Serguei Fedorov

2
@SergueiFedorov: no, non è così
Algoman

Risposte:


129

Se hai spesso bisogno di accedere all'N-esimo elemento di una sequenza, std::listche è implementato come una lista doppiamente collegata, probabilmente non è la scelta giusta. std::vectoro std::dequeprobabilmente sarebbe meglio.

Detto questo, puoi ottenere un iteratore per l'ennesimo elemento usando 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'
}

Per un contenitore che non fornisce l'accesso casuale, ad esempio std::list, std::advancechiama operator++i Ntempi dell'iteratore . In alternativa, se l'implementazione della libreria standard lo fornisce, puoi chiamare std::next:

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

std::nextis effettivamente avvolge una chiamata a std::advance, rendendo più facile far avanzare un iteratore Ncon meno righe di codice e meno variabili mutabili. std::nextè stato aggiunto in C ++ 11.


18
Mentre si paga una penalità sulle prestazioni per la ricerca in un elenco collegato a causa della mancanza di accesso casuale, si paga una penalità molto maggiore sulle prestazioni se è necessario inserire o rimuovere dati nel mezzo di un vettore o deque. La domanda in realtà non contiene informazioni sufficienti per decidere se stanno utilizzando il contenitore ideale per i loro scopi.
tloach

1
Vale la pena notare che quando si utilizza std::advanceo std::next, è facile richiamare UB. Non c'è controllo dei limiti.
okovko

33

std::listnon fornisce alcuna funzione per ottenere l'elemento dato un indice. Puoi provare a ottenerlo scrivendo del codice, cosa che non consiglierei, perché sarebbe inefficiente se ne avessi bisogno spesso.

Quello che vi serve è: std::vector. Usalo come:

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 

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
}

3

Forse non è il modo più efficiente. Ma potresti convertire l'elenco in un vettore.

#include <list>
#include <vector>

list<Object> myList;

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

Quindi accedere al vettore utilizzando l'operatore [x].

auto x = MyVector[0];

Potresti metterlo in una funzione di supporto:

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

Quindi usa la funzione di supporto in questo modo:

auto MyVector = ListToVector(Object);
auto x = MyVector[0];
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.