Search code examples
c++algorithmlambdafind

How to find an element in a vector of class objects, based on one of the class members, and delete it


I have a vector of classes. Each class has two member variables, a name (string) and time spent working (integer). My goal is simply delete an element of an array that contains a specific name.

I know I cannot use the find() algorithim, so I'm trying with the find_if() algorithim. I'm have tried making my own boolean function, which is not working. So I tried with a lambda function with the same bad results.

Reading the documentation for find_if. Apparently I need to give it a callable object, like a pointer. But if so, how would I pass my Employee class, to compare the member function name of it and also the word that I want to compare it with?

Here's my code:

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <string_view>
#include <string>

//First problem is using class and std::vector
//Track employees and time worked
class Employee
{
public:
    std::string_view m_name{};
    int m_time{};

    Employee(std::string_view name, int time)
    :m_name{name}, m_time {time}
    {
    }
};

void printEmployees(const std::vector<Employee>& employee)
{
    for (const auto& a: employee)
    {
        std::cout << a.m_name << " " << a.m_time << "\n";
    }

}

bool findEmployee(Employee &employee, std::string_view myWord)
{
    if (myWord == employee.m_name)
        return true;

    else
        return false;
}



int main()
{
    std::vector<Employee> employee{   {"Daniel Ramirez", 14},
                                      {"Marta Martinez", 55},
                                      {"Joseph Martin", 100}
                                           };


    // erase the element that contains "Marta Martinez" on the array:
    std::string myWord{"Marta Martinez"};

    // auto it { std::find_if(employee.begin(),employee.end(), findEmployee(employee, myWord) ) };


    //using lambda
    auto it { std::find_if(employee.begin(),employee.end(),   [](const Employee& employee, std::string_view myWord)
                                                                                    {
                                                                                        if (myWord == employee.m_name)
                                                                                            return true;

                                                                                        else
                                                                                            return false;
                                                                                    }) };

    if (it == employee.end())           // check if element was found
        std::cout << "Element wasn't found";


    //printEmployees(employee);
    return 0;
}

Error:

error: no matching function for call to object of type '(lambda at /Users/danielramirez/CLionProjects/test/main.cpp:81:63)'
        if (__pred(*__first))

I know I'm doing something wrong in terms of implementing the 3rd argument of the find_if algorithm. Any help is really appreciated.


Solution

  • find_if takes a single-argument lambda. You don't need to pass myWord into it, you just capture it (using e.g. [&] - "capture all by reference by default").

    [&](const Employee& employee)
    {
        return myWord == employee.m_name;
    }
    

    You can also simplify if (x) return true; else return false; to just return x;, as shown.


    Then you pass the resulting iterator to employee.erase(it); (if it's not .end()) to delete the element.

    Or you can use std::erase_if(employee, /*same lambda as a above*/); oneliner to delete all matches.