Wie bekomme ich ein bestimmtes Element in eine Liste angesichts der Position?

92

Also habe ich eine Liste:

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

Ich bin nicht sicher, aber ich bin zuversichtlich, dass dies das "0." Element im Array sein wird. Gibt es eine Funktion, die "myObject" zurückgibt?

Object copy = myList.find_element(0);

?

Prüfung
quelle
8
Es gibt kein Array - es ist eine Liste. Wenn Sie nach Ganzzahlen indizieren möchten, warum verwenden Sie nicht vectorstattdessen?
Paul J. Lucas
2
Wenn Sie immer Element 0 möchten, verwenden Sie front().
Paul J. Lucas
Ich habe dies nicht getestet, aber ich würde annehmen, dass myList.front () + num hier funktionieren würde
Serguei Fedorov
2
@ SergueiFedorov: Nein, tut es nicht
Algoman

Antworten:

129

Wenn Sie häufig auf das N-te Element einer Sequenz zugreifen müssen std::list, das als doppelt verknüpfte Liste implementiert ist, ist dies wahrscheinlich nicht die richtige Wahl. std::vectoroder std::dequewäre wahrscheinlich besser.

Das heißt, Sie können einen Iterator für das N-te Element erhalten, indem Sie 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'
}

Für einen Container, der keinen wahlfreien Zugriff bietet std::list, std::advancewerden beispielsweise operator++die Iteratorzeiten aufgerufen N. Wenn Ihre Standardbibliotheksimplementierung dies bereitstellt, können Sie alternativ Folgendes aufrufen std::next:

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

std::nextDies schließt einen Aufruf effektiv ab std::advanceund erleichtert so das Vorrücken von Iteratorzeiten Nmit weniger Codezeilen und weniger veränderlichen Variablen. std::nextwurde in C ++ 11 hinzugefügt.

James McNellis
quelle
18
Während Sie eine Leistungsstrafe zahlen, wenn Sie eine verknüpfte Liste durchsuchen, weil kein Direktzugriff vorhanden ist, zahlen Sie eine viel größere Leistungsstrafe, wenn Sie Daten in der Mitte eines Vektors oder einer Deque einfügen oder entfernen müssen. Die Frage enthält nicht genügend Informationen, um zu entscheiden, ob sie den idealen Container für ihre Zwecke verwenden.
Tloach
1
Es ist erwähnenswert, dass es bei Verwendung von std::advanceoder std::nexteinfach ist, UB aufzurufen. Es gibt keine Überprüfung der Grenzen.
Okovko
33

std::listbietet keine Funktion zum Abrufen eines Elements mit einem Index. Sie können versuchen, es zu erhalten, indem Sie Code schreiben, den ich nicht empfehlen würde, da dies ineffizient wäre, wenn Sie dies häufig tun müssen.

Was Sie brauchen ist : std::vector. Verwenden Sie es als:

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
quelle
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
quelle
3

Vielleicht nicht der effizienteste Weg. Sie können die Liste jedoch in einen Vektor konvertieren.

#include <list>
#include <vector>

list<Object> myList;

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

Greifen Sie dann mit dem Operator [x] auf den Vektor zu.

auto x = MyVector[0];

Sie könnten das in eine Hilfsfunktion einfügen:

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

Verwenden Sie dann die Hilfsfunktion wie folgt:

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