Search code examples
c++lambdafindunordered-mapstdmap

Can find_if be used to find a key in std::map/std::unordered_map?


This is a simple program consisting of adding an element into the std::unordered_map. But before it's added, first check if the key already exists, if it does then don't add it.

My problem is that since find_if requires only one parameter to be passed in the lambda function, I'm having trouble implementing this since an element on the std::unordered_map is a pair of two types. I wonder if it's even possible to use find_if and if not what's the best way to accomplish this?

#include <iostream>
#include <unordered_map>

std::unordered_map <std::string_view, int> myDictionary{};

void addEmployee(std::string_view newName, int newTime)
{
    // first check if they name already exists, if it does then do nothing and return
    auto it{std::find_if(myDictionary.begin(), myDictionary.end(),
                         [&newName]( ??? )
    {
        return newName == myDictionary.first;
    })};

    if (it != myDictionary.end() )
    {
        std::cout << "Name already exists! Wasn't added.\n";
        return;
    }

    // add employee into the map
    myDictionary.insert(std::pair<std::string_view,int> (newName, newTime) );

}

void printDict( std::unordered_map<std::string_view, int>& myDict)
{
    for (auto const& a: myDict)
        std::cout << a.first << " " << a.second << "\n";
}
int main()
{

    addEmployee("Daniel", 14);
    addEmployee("Marco", 433);
    addEmployee("Daniel", 500);     //Should not add it, since key already exists
    addEmployee("Alan", 125);

    printDict(myDictionary);

    return 0;
}

My research so far, and opens questions that I'm still trying to figure out:

  • Since std::unordered_map only add uniques keys, it will not add it anyways if I directly insert it, so no need for a check before it (?)
  • Going through the documentation for std::unordered_map, I only found find as member function, not find_if, so I'm assuming this is why it cannot be used. If not, then is find the best way to implement this program or using some other alternative like [] work better. (?)

Thanks a lot


Solution

  • Since the name is the key in your unordered_map, you can simply use the unordered_map::find method to check whether it exists:

    void addEmployee(std::string_view newName, int newTime)
    {
        // first check if they name already exists, if it does then do nothing and return
        auto it = myDictionary.find(newName);
        if (it != myDictionary.end())
        {
            std::cout << "Name already exists! Wasn't added.\n";
            return;
        }
        // add employee into the map
        myDictionary.insert(std::pair<std::string_view, int>(newName, newTime));
    }
    

    Live demo

    Some notes for completeness:

    1. To answer your explicit question: find_if can also be used, but I see no advantage of using it over the straightforward find method (which is designed exactly for this purpose - search for an entry by key). An example is shown in the answer by @Yksisarvinen (see that answer also for another alternative - using insert by itself).
    2. std::string_view does not own the string it refers to. It's OK in your case (as posted) because you used string literals but if you need to create new strings it will be more robust to use std::strings as keys.