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

В этом примере я создаю связанный список из 4 объектов Person, каждый из которых имеет возраст. Я хотел бы перебрать список лиц, отследить самого молодого человека, а затем удалить этого человека из списка.

Вот что у меня есть

#include <iostream>
#include <vector>
#include <list>

struct Person
{
    Person(int x): age(x) {}

    int age;
};

int main() {

    // Create 4 Person instances
    Person p1 = Person(50);
    Person p2 = Person(35);
    Person p3 = Person(99);
    Person p4 = Person(17);

    // Build a list of persons
    std::list<Person> persons = {p1, p2, p3, p4};

    // Delete the list-element of the youngest person
    int minAge = 999;            // track the lowest age so far
    Person* youngin = nullptr;  // track the person with the lowest age so far

    // Iterate through each person in the list, looking for someone with a lower age than all previous
    for(auto const &p : persons){
        if (p.age < minAge){
            std::cout << "Found someone younger. Age: " << p.age << std::endl;

            // Update minAge and youngin
            minAge = p.age;
            // youngin = ???;
        }
    }

    // Delete the youngest person from the list
    // persons.erase(youngin);

    return 0;
}

Как мне 1) сохранить указатель (я думаю?) На самого молодого человека «на данный момент» и 2) удалить этот элемент из списка в конце?


ОБНОВИТЬ

Кажется, я слишком упростил свой минимально воспроизводимый пример. @NathanOliver, похоже, имеет лучшее решение для того, о чем я просил, поэтому я выберу его в качестве принятого, но если кто-то захочет помочь мне в дальнейшем,

Предположим, что пятого человека нет в списке,

Person p5 = Person(30);

Теперь, как мне определить, кто из 4 человек в списке наиболее близок по возрасту к p5, и затем удалить этого человека из списка? (В этом случае p2 должен быть идентифицирован и удален.) Я не вижу, как применить решение Натана с использованием std::min_element в этой ситуации.

Ваше здоровье

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
115
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

persons.erase(std::min_element(persons.begin(), 
                               persons.end(), 
                               [](auto const& lhs, auto const& rhs){ return lhs.age < rhs.age; }));

Если вам нужно использовать минимум, прежде чем избавляться от него, вы можете разделить вызов, например

auto min_it = std::min_element(persons.begin(), 
                               persons.end(), 
                               [](auto const& lhs, auto const& rhs){ return lhs.age < rhs.age; }));
//use min_it here
person.erase(min_it); // get rid of the minimum

Обновлять:

Вы все еще можете использовать min_element для поиска элемента, нам просто нужно найти минимальную разницу вместо минимального элемента. Нам просто нужно изменить лямбду на, чтобы сравнивать разницу в возрастах и ​​значение, которое нужно найти, а не только на возраст.

Person p5 = Person(30);
persons.erase(std::min_element(persons.begin(), 
                               persons.end(), 
                               [&](auto const& lhs, auto const& rhs){ 
                                   return std::abs(lhs.age - p5.age) < std::abs(rhs.age - p5.age);
                               }));

Я использовал [&] в лямбде, поэтому он захватывает p5 по ссылке, чтобы мы могли вычислить разницу. Вы можете увидеть это в живой пример.

Если OP заинтересован, Смотрите вживую.

WhozCraig 18.12.2018 21:51

Спасибо, но, похоже, я упростил свой пример (извините !!). Предположим, что пятого человека, p5, нет в списке. Как мне определить человека, ближайшего к p5 по возрасту, и удалить его из списка?

Ben 18.12.2018 21:58

@Ben Я обновил ответ, указав способ решения обновления.

NathanOliver 18.12.2018 22:22

@Ben Они очень удобны. здесь - хороший справочник, а здесь - достойный разговор о них.

NathanOliver 18.12.2018 22:27

Ваш первоначальный ответ сам по себе был отличным, но тот факт, что вы продолжали обновлять дополнительную информацию и помогать OP в дальнейшем, просто фантастический!

Tas 18.12.2018 22:55

Типом p является std::list<Person>::iterator (поскольку он должен быть классом «узла», в большинстве случаев хранящим указатель на следующий узел и значение узла).

std::list::erase принимает итератор, тогда как цикл for разыменовывает итератор, поэтому вы не получаете итератор.

Итак, вам нужно использовать std::list::begin и std::list::end для получения итераторов.

typename std::list<Person>::iterator youngin;  // track the person with the lowest age so far
// Or:
decltype(persons.cbegin()) youngin;

// Iterate through each person in the list, looking for someone with a lower age than all previous
for (auto it = persons.cbegin(); it != persons.cend(); ++it){
    if (p->age < minAge) {
        std::cout << "Found someone younger. Age: " << p.age << std::endl;

        // Update minAge and youngin
        minAge = p->age;
        youngin = it;
    }
}

// Delete the youngest person from the list
persons.erase(youngin);

Если вам не нужно использовать указатель, этот код должен:

int main() {
    // Build a list of persons
    std::list<Person> persons = {Person(50), Person(35), Person(99), Person(17)};

    Person yongestPerson = persons[0];

    // looking for someone with a lower age than all previous yongestPerson
    for(persons p : persons){
        if (p.age < yongestPerson.age){
            std::cout << "Found someone younger. Age: " << p.age << std::endl;

            // Update minAge and youngin
            yongestPerson = p
        }
    }

    // Delete the youngest person from the list
    persons.remove(yongestPerson);

    return 0;
}

Для работы Person необходим operator==. У OP в настоящее время его нет.

NathanOliver 18.12.2018 21:58

Другие вопросы по теме