Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ To filter a class vector using algorithm

How can I filter a class vector, studentList by its country from using algorithm? Meaning I only display the detail of students from country "America".

bool checkCountry (string x, string y) 
{
  return (x == y);
}
vector<Student> studentList;
studentList.push_back(Student("Tom", 'M', "91213242", "America"));
studentList.push_back(Student("Jessilyn", 'F', "98422333", "Europe"));
like image 992
delphi316 Avatar asked Jan 17 '12 15:01

delphi316


4 Answers

using std::copy_if;
using std::ostream_iterator;
using std::cout;

enum Region {
    AMERICA,
    EUROPE,
    REST_OF_WORLD
};

bool is_american(const Student& student)
{
    return student.isFrom(AMERICA);
}

copy_if(students.begin(), students.end(),
        ostream_iterator<Student>(cout, "\n"),
        is_american);

Using a lambda in C++11, and allowing chosen regions:

void show_students_from_region(const Region& region)
{
    copy_if(students.begin(), students.end(),
            ostream_iterator<Student>(cout, "\n"),
            [&](const Student& student) { return student.isFrom(region); });
}
like image 129
Peter Wood Avatar answered Nov 16 '22 19:11

Peter Wood


You can use filter_iterator from boost. Here is an example with the underlying collection being an ordinary array.

Below is example untested code for you to play with; I had to make certain assumptions about Student (operator<< valid for output, country exposed via std::string country() const)

struct checkCountry
{
  std::string country;
  bool operator()(const Student& x) 
  {
    return (x.country() == country);
  }
};

int main()
{
  std::vector<Student> studentList;
  studentList.push_back(Student("Tom", 'M', "91213242", "America"));
  studentList.push_back(Student("Jessilyn", 'F', "98422333", "Europe"));

  typedef boost::filter_iterator<checkCountry, std::vector<Student>::iterator> FilterIter;
  checkCountry predicate;
  predicate.country = "America";
  FilterIter filter_iter_first(predicate, studentList.begin(), studentList.end());
  FilterIter filter_iter_last(predicate,  studentList.end(),  studentList.end());

  std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<Student>(std::cout, " "));
}
like image 33
bronekk Avatar answered Nov 16 '22 19:11

bronekk


I think this what you are looking for:

struct country_filter
{
    country_filter(const std::string& a_country): country(a_country) {}
    void operator()(const Student& a_s) const
    {
        if (country == a_s.country)
        {
            std::cout << a_s.name << "\n";
        }
    }
    std::string country;
};

// 
std::for_each(studentList.begin(), studentList.end(), country_filter("Ireland"));

C++11:

std::string country = "America";
std::for_each(studentList.begin(), studentList.end(), [&country] (const Student& a_s)
{
    if (a_s.country == country)
    {
        std::cout << a_s.name << "\n";
    }
});
like image 21
hmjd Avatar answered Nov 16 '22 18:11

hmjd


You can use an object of a class that implements the () operator. This is called a functor:

struct checkCountry {
  const string& compare;
  checkCountry(const string& compare) : compare(compare) {}
  bool operator()(const string& x) { return x == compare; }
};

vector<Student> studentList;
studentList.push_back(Student("Tom", 'M', "91213242", "America"));
studentList.push_back(Student("Jessilyn", 'F', "98422333", "Europe"));
howMany = std::count_if(studentList.begin(), studentList.end(), checkCountry("America"));

You can use a functor in any algorithm that requires an unary predicate, for example, std::count_if, std::find_if, etc.

like image 6
Robᵩ Avatar answered Nov 16 '22 17:11

Robᵩ