Как получить определенный элемент в списке, учитывая позицию?

93

Итак, у меня есть список:

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

Я не уверен, но уверен, что это будет «0-й» элемент в массиве. Могу ли я использовать какую-либо функцию, которая вернет myObject?

Object copy = myList.find_element(0);

?

Контрольная работа
источник
8
Массивов нет - это список. Если вы хотите индексировать по целому числу, почему бы вам не использовать vectorвместо этого?
Пол Дж. Лукас,
2
Если вам всегда нужен элемент 0, используйте front().
Пол Дж. Лукас,
Я не тестировал это, но предполагаю, что myList.front () + num будет работать здесь
Сергей Федоров
2
@SergueiFedorov: нет, это не так
Algoman

Ответы:

129

Если вам часто требуется доступ к N-му элементу последовательности, std::listкоторый реализован как двусвязный список, вероятно, это неправильный выбор. std::vectorили std::deque, вероятно, было бы лучше.

Тем не менее, вы можете получить итератор для N-го элемента, используя 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'
}

Для контейнера, который не предоставляет произвольный доступ, например std::list, std::advanceвызывает operator++время итератора N. В качестве альтернативы, если ваша реализация стандартной библиотеки предоставляет это, вы можете вызвать std::next:

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

std::nextэффективно обертывает вызов std::advance, облегчая продвижение Nвремени итератора с меньшим количеством строк кода и меньшим количеством изменяемых переменных. std::nextбыл добавлен в C ++ 11.

Джеймс МакНеллис
источник
18
Хотя вы платите штраф за производительность при поиске связанного списка из-за отсутствия произвольного доступа, вы платите гораздо больший штраф за производительность, если вам нужно вставить или удалить данные в середине вектора или двухсторонней очереди. Вопрос на самом деле не содержит достаточно информации, чтобы решить, используют ли они идеальный контейнер для своих целей.
tloach
1
Стоит отметить, что при использовании std::advanceили std::nextлегко вызвать UB. Нет проверки границ.
okovko
34

std::listне предоставляет никакой функции для получения элемента по индексу. Вы можете попытаться получить его, написав код, что я бы не рекомендовал, потому что это было бы неэффективно, если вам часто нужно это делать.

Что вам нужно: std::vector. Используйте это как:

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

Может, не самый действенный способ. Но вы можете преобразовать список в вектор.

#include <list>
#include <vector>

list<Object> myList;

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

Затем обратитесь к вектору с помощью оператора [x].

auto x = MyVector[0];

Вы можете поместить это во вспомогательную функцию:

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

Затем используйте вспомогательную функцию следующим образом:

auto MyVector = ListToVector(Object);
auto x = MyVector[0];
Билл Мур
источник