2012-01-21 2 views
1

Мой remove_if, кажется, перезаписывает элементы, которые не отфильтровываются со значениями отфильтрованных элементов. Цель этого кода - разрешить пользователю фильтровать и отображать только учителя из определенной категории. (Не удалять любой элемент) Вот некоторые из кодаC++ 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

Какой вход, ожидаемый выход и фактический выход? –

+0

Как вы можете видеть из кода, пользователь может ввести только 1,2 или 3, для какой категории они хотят фильтровать. Для ожидаемого результата он должен отображать только учителя из категории, которую выбрал пользователь. Фактический вывод вышел правильно, если есть только один объект с категорией, соответствующей «compare», но если есть 2 объекта с категорией, соответствующей «compare», он начинает перезаписывать объекты в векторе – delphi316

ответ

2

remove_if сдвигает элементы, для которых функция сравнения возвращает false, справа налево; который, другими словами, означает, что он перезаписывает элементы, для которых compare возвращает true, с элементами, для которых compare возвращает false. Однако размер вектора не изменяется.

This reads,

Удаляет все элементы, удовлетворяющие определенным критериям из диапазона [первый, последний). Первая версия удаляет все элементы, которые равны значению, вторая версия удаляет все элементы, для которых предикат p возвращает true.

Снятие осуществляется путем смещения элементов в диапазоне таким образом, что элементы, подлежащие стиранию, перезаписываются. Элементы между старым и новым концами диапазона имеют неопределенные значения. Возвращается Iterator в новый конец диапазона. Относительный порядок оставшихся элементов сохраняется.

Так что вы хотите сделать, должно быть выражено как:

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.
  • Вы должны понимать разницу между iterator и const_iterator и их использованием.
  • Вы должны понимать разницу между константной ссылкой и неконстантной ссылкой. И попробуйте использовать их соответствующим образом.

Так что я бы написать свой код, как:

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

Как было отмечено в комментариях: getCat, getName и getCategory должны быть константные функции-члены. Фактически, если getCategory возвращает категорию, то getCat даже не требуется.

Решил мою проблему.

+1

+1 для объяснения на простом ясном языке. Нет элементов в контейнере не изменится, если они явно не стираются. –

+0

Я понимаю вашу кодировку, но есть ли способ сделать это с помощью алгоритма? – delphi316

+0

@NewUserSeekingHelp: Даже если есть способ, это было бы достаточно сложно, чтобы этого избежать. Нет простого способа сделать это, используя ''. Кроме того, вам следует больше сосредоточиться на общем коде и других проблемах в вашем коде, как я предложил в повторной записи вашего кода. – Nawaz

1

remove_if собирает значения, для которых filter_Cat возвращает ложь в начале контейнера. Хотя он не уменьшает количество элементов в контейнере, он также не дает никаких гарантий относительно значений элементов за пределами возвращаемого диапазона. Таким образом, вы теряете значения при использовании remove_if.

+0

Итак, что было бы лучше вариант для моего случая? – delphi316

+0

@NewUserSeekingHelp: цикл цикла с тестом в цикле, чтобы решить, хотите ли вы его отобразить. –

+0

Любой алгоритм, который я могу применить, подходит для этого сценария? – delphi316

Смежные вопросы