В этом примере я создаю связанный список из 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
в этой ситуации.
Ваше здоровье
Вы можете использовать стандартные алгоритмы и лямбду, чтобы сделать это за вас. 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
по ссылке, чтобы мы могли вычислить разницу. Вы можете увидеть это в живой пример.
Спасибо, но, похоже, я упростил свой пример (извините !!). Предположим, что пятого человека, p5, нет в списке. Как мне определить человека, ближайшего к p5 по возрасту, и удалить его из списка?
@Ben Я обновил ответ, указав способ решения обновления.
@Ben Они очень удобны. здесь - хороший справочник, а здесь - достойный разговор о них.
Ваш первоначальный ответ сам по себе был отличным, но тот факт, что вы продолжали обновлять дополнительную информацию и помогать OP в дальнейшем, просто фантастический!
Типом 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 в настоящее время его нет.
Если OP заинтересован, Смотрите вживую.