【问题标题】:C++ remove_if overwriting my vectorC++ remove_if 覆盖我的向量
【发布时间】:2012-01-21 05:55:19
【问题描述】:

我的 remove_if 似乎正在用过滤掉的元素的值覆盖未过滤掉的元素。这些代码的目的是允许用户过滤和仅显示某个类别的教师。 (不删除任何元素) 以下是部分代码

static string compare;
static string debug;

bool filter_Cat (Teacher &t) 
{ 
    return (t.getCat() != compare); 
}

void filterCat (vector<Teacher> &t)
{
   vector<Teacher>::iterator i;
   vector<Teacher>::iterator newedited = remove_if(t.begin(), t.end(), filter_Cat);
   for (i = t.begin(); i != newedited; ++i)
   {
     Teacher& te = *i;
     te.getName();
     cout << "\t";
     te.getCategory();
     cout << "\t";
     te.getLocation();
   }
 }

 void filterTutorCat(vector<Teacher> &t)
 {
    int choice;
    cout << "No\tCategory" << endl
         << "1\tEnglish" << endl
         << "2\tMath" << endl
         << "3\tScience" << endl
         << "Choose the category you wish to filter :";
    cin >> choice;
    getline(cin, debug);

    if(choice <= 3 && choice > 0)
    {
        if (choice == 1)
        {
          compare = "English";
          filterCat(t);
        }
        if (choice == 2)
        {
          compare = "Math";
          filterCat(t);
        }
        if (choice == 3)
        {
          compare = "Science";
          filterCat(t);
        }

    }
    else
    {
        cout << "Invalid Option" << endl;
    }
 }

【问题讨论】:

  • 输入、预期输出和实际输出是什么?
  • 从代码中可以看出,用户只能输入 1,2, 或 3 他们希望过滤的类别。对于预期的输出,它应该只显示用户选择的类别中的教师。如果只有一个类别与“比较”匹配的对象,则实际输出正确,但如果有 2 个类别与“比较”匹配的对象,则开始覆盖向量中的对象

标签: c++ vector remove-if


【解决方案1】:

remove_if 将比较函数返回 false 的元素从右向左移动;换句话说,它用比较返回 false 的元素覆盖比较返回 true 的元素。但是,向量的大小不会改变。

This reads,

从范围 [first, last) 中删除所有满足特定条件的元素。第一个版本删除所有等于 value 的元素,第二个版本删除所有谓词 p 返回 true 的元素。

删除是通过移动范围中的元素以覆盖要删除的元素来完成的。范围的新旧两端之间的元素具有未指定的值。返回范围新结尾的迭代器。保留剩余元素的相对顺序。

所以你想做的应该表达为:

void filterCat (vector<Teacher> &v)
{
   for (vector<Teacher>::iterator it = v.begin(); it != v.end() ; ++it)
   {
      if (!filter_Cat(*i))
      {
           std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
      }
   }
 }

似乎在您的代码中,getName() 打印了理想情况下不应该这样做的名称,而是应该返回名称。因此,我建议您对其进行更改以使其返回名称。对getCategory 也做同样的事情。正确选择你的名字。如果是getName(),你应该得到你的名字,返回它;如果是printName(),那么它应该打印名字。


另外,你写的代码也不好:

  • 您应该避免使用全局变量。
  • 您应该尽可能避免使用 if-else。学习更好的方法。
  • 您应该了解函数对象(或函子)
  • 你应该了解const成员函数。
  • 您应该了解iteratorconst_iterator 之间的区别以及它们的用法。
  • 您应该了解 const 引用和非 const 引用之间的区别。并尝试适当地使用它们。

所以我会把你的代码写成:

//this is functor, not a function
struct filter_cat
{
   std::string m_cat; //use member data, avoid global variable
   filter_cat(std::string const & cat) : m_cat(cat) {}
   bool operator()(Teacher const & t) const  //const member function
   { 
     return (t.getCat() != m_cat); //getCat should be const member function
   }
};

//pass vector by const reference
void filterCat (vector<Teacher> const & v, filter_cat filter)
{
   //use const_iterator here, instead of iterator 
   for (vector<Teacher>::const_iterator it = v.begin(); it != v.end() ; ++it)
   {
      if (!filter(*i))
      {
           //getName and getCategory should be const member function
           std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
      }
   }
}

void filterTutorCat(vector<Teacher> const &t)
{
    int choice;
    cout << "No\tCategory" << endl
         << "1\tEnglish" << endl
         << "2\tMath" << endl
         << "3\tScience" << endl
         << "Choose the category you wish to filter :";
    cin >> choice;
    getline(cin, debug);

    //avoid if-else as much as possible, learn better ways!
    std::string cats[] = {"English", "Math", "Science"};

    if(choice <= 3 && choice > 0)
    {
          filterCat(v, filter_cat(cats[choice-1]));
    }
    else
    {
        cout << "Invalid Option" << endl;
    }
}

如 cmets 中所述:getCatgetNamegetCategory 应该是 const 成员函数。事实上,如果getCategory 返回类别,那么甚至不需要getCat

解决了我的问题。

【讨论】:

  • +1 以简单清晰的语言进行解释。容器中的元素数量不会改变,除非它们是明确的erased。
  • 我了解你的编码,但有没有办法用算法做到这一点?
  • @NewUserSeekingHelp:即使有办法,它也足够复杂以避免它。使用&lt;algorithm&gt; 没有直接的方法可以做到这一点。此外,您应该更多地关注整体代码以及代码中的其他问题,正如我在重写代码时所建议的那样。
  • 非常感谢您指出我的错误,但问题是我的讲师坚持要我们演示 stl 算法的使用
  • @Nawaz 感谢您的帮助,但我已经解决了这个问题。经过您的更正,我觉得我的编码道德有所提高!再次非常感谢你..
【解决方案2】:

remove_if 收集 filter_Cat 在容器开始时返回 false 的值。虽然它不会减少容器中元素的数量,但它也不会对超出返回范围的元素值做出任何保证。所以你在使用 remove_if 时会失去价值。

【讨论】:

  • 那么对于我的情况有什么更好的选择?
  • @NewUserSeekingHelp:一个for循环,在循环中有一个测试来决定是否要显示它。
  • 我可以应用任何适合这种情况的算法吗?
  • @NewUserSeekingHelp:您可以使用remove_if,但您希望在向量的副本上执行此操作,而不是在实际向量上。这是完成任务的一种非常低效的方式,但它会做你想要的。您可以通过简单地从函数参数中删除与符号来修改当前代码。即void filterCat (vector&lt;Teacher&gt; t)——然后你按值获取向量。制作了一份副本,所有修改都不会影响原件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 2017-02-25
  • 2011-06-11
相关资源
最近更新 更多