【问题标题】:When iterating through a list, how do I keep track of a list element to be deleted later on?遍历列表时,如何跟踪稍后要删除的列表元素?
【发布时间】:2018-12-18 20:39:32
【问题描述】:

在这个例子中,我构建了一个包含 4 个 Person 对象的 linked list,每个对象都有一个 age。我想遍历 Persons 列表,跟踪最年轻的人,然后从列表中删除该人。

这是我目前所拥有的

#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 似乎对我的要求有最好的解决方案,所以我会选择他作为接受但如果有人愿意进一步帮助我,

假设有第 5 个人不在列表中,

Person p5 = Person(30);

现在,我如何确定列表中的 4 个人中哪一个的年龄与 p5 最接近,然后从列表中删除该人? (在这种情况下,p2 应该被识别并删除。)我不知道如何将 Nathan 的解决方案使用 std::min_element 应用于这种情况。

干杯

【问题讨论】:

    标签: c++


    【解决方案1】:

    您可以使用标准算法和 lambda 为您完成这项工作。 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 来查找元素,我们只需要找到最小差异而不是最小元素。我们只需要改变 lambda 来比较年龄和要查找的值的差异,而不是仅仅比较年龄。

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

    我在 lambda 中使用了[&amp;],因此它通过引用捕获p5,以便我们计算差异。您可以在 live example 中看到它的工作原理。

    【讨论】:

    • 如果 OP 感兴趣,See it live.
    • 谢谢,但我的例子似乎过于简单了(对不起!!)。相反,假设有第 5 个人 p5 不在列表中。如何识别年龄与 p5 最接近的人并将其从列表中删除?
    • @Ben 我已经用解决更新的方法更新了答案。
    • @Ben 他们非常方便。 here 是一个很好的参考,here 是一个不错的讨论。
    • 您的原始答案本身很棒,但是您不断更新更多信息并进一步帮助 OP 的事实真是太棒了!
    【解决方案2】:

    p 的类型是std::list&lt;Person&gt;::iterator(因为它需要是“节点”类,在大多数情况下存储指向下一个节点的指针和节点的值)。

    std::list::erase 采用迭代器,而 for 循环取消引用迭代器,因此您不会得到迭代器。

    因此,您需要使用std::list::beginstd::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);
    

    【讨论】:

      【解决方案3】:

      如果你不必使用指针,这段代码应该这样做:

      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 目前没有。
      猜你喜欢
      • 2013-08-05
      • 2017-02-08
      • 2012-12-05
      • 1970-01-01
      • 2014-04-12
      • 2012-06-13
      • 2010-11-24
      • 2018-06-27
      • 2019-10-16
      相关资源
      最近更新 更多