Як отримати певний елемент у списку, враховуючи позицію?


92

Отже, у мене є список:

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

Я не впевнений, але впевнений, що це буде "0-й" елемент у масиві. Чи є якась функція, яку я можу використовувати, яка повертає "myObject"?

Object copy = myList.find_element(0);

?


8
Масиву немає - це список. Якщо ви хочете індексувати за цілим числом, чому б вам не використовувати vectorзамість цього?
Пол Дж. Лукас,

2
Якщо ви завжди хочете елемент 0, використовуйте front().
Paul J. Lucas,

Я цього не тестував, але припускаю, що тут буде працювати myList.front () + num
Сергей Федоров

2
@SergueiFedorov: ні, ні
Альгоман

Відповіді:


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було додано в С ++ 11.


18
Поки ви платите штраф за продуктивність за пошук у зв’язаному списку через відсутність довільного доступу, ви платите набагато більший штраф за продуктивність, якщо вам потрібно вставити або видалити дані в середині вектора чи дека. Питання насправді не містить достатньо інформації, щоб вирішити, чи використовують вони ідеальний контейнер для своїх цілей.
tloach

1
Варто зазначити, що при використанні std::advanceабо std::nextлегко викликати UB. Тут немає перевірки меж.
okovko

33

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];
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.