Предотвратить дубликаты в векторе - PullRequest
0 голосов
/ 07 ноября 2018

Я пытаюсь предотвратить добавление дубликатов в функцию add_child, но пока безуспешно. Не могли бы вы помочь мне, как это сделать? Заранее спасибо.

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

using namespace std;

void add_family(map<string, vector<string>> &family, 
                const string &name)
{
    if (family.find(name) == family.end())
    {
        family.insert({name, vector<string>()});
    }
    else
    {
        cerr << "Error: Already has family <" << name << ">" << endl;
    }
}

void add_child(map<string, vector<string>> &family, const string 
               &family_name, const string &child_name)
{
    auto it = family.find(family_name);

    if (it != family.cend())
    {

        it->second.push_back(child_name);
    }
    else
    {
        cerr << "Error: No family <" << family_name << 
                "> for child <" << child_name << ">" << std::endl;
    }
}

int main(int argc, char const *argv[])
{
    map<string, vector<string>> family;
    add_family(family, "Family1");
    add_family(family, "Family2");
    add_family(family, "Family1"); // Error

    add_child(family, "Family1", "Name1");
    add_child(family, "Family1", "Name2");
    add_child(family, "Family1", "Name3");
    add_child(family, "Family1", "Name3"); //will create duplicate
    add_child(family, "Family2", "Name1");
    add_child(family, "Family2", "Name2");
    add_child(family, "Family2", "Name3");
    add_child(family, "Family3", "Name1"); // Error

    for (const auto &f : family)
        for (const auto &name : f.second)
            cout << f.first << " " << name << endl;
    return 0;
}

Вывод программы:

Error: Already has family <Family1>
Error: No family <Family3> for child <Name1>
Family1 Name1
Family1 Name2
Family1 Name3
Family1 Name3
Family2 Name1
Family2 Name2
Family2 Name3

1 Ответ

0 голосов
/ 07 ноября 2018

Как отмечается в комментариях, вы проверяете только дубликаты family_name, а не child_name. Вы можете использовать std::find для поиска std::vector

void add_child(map<string, vector<string>> &family, const string & family_name, const string & child_name)
{
    auto f_it = family.find(family_name);

    if (f_it != family.cend())
    {
        auto c_it = find(f_it->second.begin(), f_it->second.end(), child_name);
        if (c_it == f_it->second.end())
        {
            f_it->second.insert(c_it, child_name);
        }
        else
        {
            cerr << "Error: Already has child <" << child_name << ">" << endl;
        }
    }
    else
    {
        cerr << "Error: No family <" << family_name << 
                "> for child <" << child_name << ">" << std::endl;
    }
}

Или же вы можете использовать std::map<std::string, std::set<std::string>> для обеспечения уникальности. Кроме того, вы можете использовать возвращаемое значение insert, чтобы искать каждое имя только один раз.

void add_family(map<string, set<string>> &family, const string &name)
{
    if (!family.insert({name, {}}).second)
    {
        cerr << "Error: Already has family <" << name << ">" << endl;
    }
}

void add_child(map<string, set<string>> &family, const string & family_name, const string & child_name)
{
    auto it = family.find(family_name);

    if (it == family.cend())
    {
        cerr << "Error: No family <" << family_name << 
                "> for child <" << child_name << ">" << std::endl;
    } else if (!it->second.insert(child_name).second)
    {
        cerr << "Error: Already has child <" << child_name << ">" << endl;
    }
}

Но я думаю, что этот дизайн не элегантен. Я бы вообще не стал беспокоиться о add_family. Просто используйте инварианты map и set.

void add_child(map<string, set<string>> &family, const string & family_name, const string & child_name)
{
    family[family_name].insert(child_name);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...