C++ remove_if 覆盖我的向量

发布于 2024-12-27 22:58:57 字数 1406 浏览 0 评论 0原文

我的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;
    }
 }

My remove_if seems to be overwriting the elements that are not filtered out with values of filtered out elements. The purpose of these code is to allow user to filter and display only teacher from a certain category. (Not deleting any element)
Here are some of the code

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白衬杉格子梦 2025-01-03 22:58:57

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

这内容为

从范围 [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;
    }
}

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

解决了我的问题。

remove_if shifts elements, for which the compare function returns false, from right to left; which in other words means, it overwrites the elements, for which compare returns true, with elements, for which compare returns false. The size of the vector doesn't change, however.

This reads,

Removes all elements satisfying specific criteria from the range [first, last). The first version removes all elements that are equal to value, the second version removes all elements for which predicate p returns true.

Removing is done by shifting the elements in the range in such a way that elements to be erased are overwritten. The elements between the old and the new ends of the range have unspecified values. Iterator to the new end of the range is returned. Relative order of the elements that remain is preserved.

So what you want to do should be expressed as:

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

It seems in your code, getName() prints the name which ideally it should not do, instead it should return name. So I would suggest you to change it to make it return name. And do the same for getCategory as well. Choose your name correctly. If it is getName(), you should get you name by returning it; if it is printName(), then it should print name.


Also, the code which you've written isn't good:

  • You should avoid global variables.
  • You should avoid if-else as much as possible. Learn better ways.
  • You should learn about function objects (or functor)
  • You should learn about const member function.
  • You should understand the difference between iterator and const_iterator, and their usage.
  • You should understand the difference between const reference, and non-const reference. And try using them appropriately.

So I would write your code as:

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

As noted in the comments: getCat, getName and getCategory should be const member functions. In fact, if getCategory returns category, then getCat isn't even needed.

Solved my issue.

听你说爱我 2025-01-03 22:58:57

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

remove_if collects the values for which filter_Cat returns false at the start of the container. While it doesn't reduce the number of elements in the container it neither does make any guarantees about the values of the elements beyond the returned range. So you are loosing values when using remove_if.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文