Jak uzyskać określony element na liście, biorąc pod uwagę pozycję?

93

Więc mam listę:

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

Nie jestem pewien, ale jestem pewien, że byłby to „zerowy” element w tablicy. Czy jest jakaś funkcja, której mogę użyć, która zwróci wartość „myObject”?

Object copy = myList.find_element(0);

?

Test
źródło
8
Nie ma tablicy - to lista. Jeśli chcesz indeksować według liczby całkowitej, dlaczego nie użyjesz vectorzamiast tego?
Paul J. Lucas
2
Jeśli zawsze chcesz mieć element 0, użyj front().
Paul J. Lucas
Nie testowałem tego, ale zakładam, że myList.front () + num działałoby tutaj
Serguei Fedorov
2
@SergueiFedorov: nie, nie robi
Algoman

Odpowiedzi:

129

Jeśli często potrzebujesz dostępu do n-tego elementu sekwencji, std::listktóry jest zaimplementowany jako lista podwójnie połączona, prawdopodobnie nie jest to właściwy wybór. std::vectorlub std::dequeprawdopodobnie byłoby lepiej.

To powiedziawszy, możesz uzyskać iterator do N-tego elementu za pomocą 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'
}

W przypadku kontenera, który nie zapewnia dostępu swobodnego, na przykład std::list, std::advancewywołuje czasy operator++iteratora N. Alternatywnie, jeśli zapewnia to implementacja biblioteki standardowej, możesz zadzwonić pod numer std::next:

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

std::nextskutecznie opakowuje wywołanie do std::advance, ułatwiając przesunięcie Nczasu iteratora z mniejszą liczbą wierszy kodu i mniejszą liczbą zmiennych podlegających mutacji. std::nextzostał dodany w C ++ 11.

James McNellis
źródło
18
Chociaż płacisz karę za wydajność przeszukiwania połączonej listy z powodu braku losowego dostępu, płacisz dużo większą stratę wydajności, jeśli musisz wstawić lub usunąć dane w środku wektora lub deque. Pytanie w rzeczywistości nie zawiera wystarczających informacji, aby zdecydować, czy używają idealnego pojemnika do swoich celów.
tloach
1
Warto zauważyć, że korzystając z std::advancelub std::next, łatwo jest wywołać UB. Nie ma sprawdzania granic.
okovko
34

std::listnie zapewnia żadnej funkcji do pobrania elementu o podanym indeksie. Możesz spróbować go zdobyć, pisząc jakiś kod, którego nie polecam, ponieważ byłoby to nieefektywne, gdybyś musiał to często robić.

Co potrzebne jest: std::vector. Użyj go jako:

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
źródło
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
źródło
3

Może nie jest to najbardziej efektywny sposób. Ale możesz przekonwertować listę na wektor.

#include <list>
#include <vector>

list<Object> myList;

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

Następnie uzyskaj dostęp do wektora za pomocą operatora [x].

auto x = MyVector[0];

Możesz umieścić to w funkcji pomocniczej:

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

Następnie użyj funkcji pomocniczej w następujący sposób:

auto MyVector = ListToVector(Object);
auto x = MyVector[0];
Bill Moore
źródło