如何删除 map<string, set<class>> 集合中的元素

How to delete an element in set of map<string, set<class>>

我有一个 class 汽车模型,我还有一个数据库 - 地图容器:map<string, set<CarModel>> 其中字符串类型是公司名称,集合包含汽车模型名称。

我想编写一个方法来删除确切公司的汽车。但我不知道怎么办。 例如,我在数据库中有一家法拉利公司,这家公司有一组车型,如 California、Barionetta 等。假设我在控制台 Del Ferrari California 中写入。如何从一组汽车模型中删除加利福尼亚?

// Add - Add a new company with a car (name, type, powervalue);
// Print - if arguments are empty, prints all the database. Also available:
// Print "companyname" (to print all models for this company)
// Print "cartype" - print all cars with this type
// Print "carname" - print an information about car;

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <exception>
#include <set>
#include <iomanip>
#include <sstream>


using namespace std;

class CarModel
{
public:
    CarModel (const string& new_name, const string& new_type, const  int& new_powerValue)
    {
        if (new_name.size() > 12 || new_name.empty())
        {
            throw out_of_range("Model name is incorrect: " + new_name);
        }
        else if (new_type.size () > 8 || new_type.empty())
        {
            throw out_of_range("Type name is incorrect " + new_type);
        }
        else if (new_powerValue > 2500 || new_powerValue < 250)
        {
            throw out_of_range("Powe Value is incorrect " + to_string(new_powerValue));
        }
        name = new_name;
        type = new_type;
        powerValue = new_powerValue;
    }

    string GetCarModelName () const
    {
        return name;
    }
    string GetCarType () const
    {
        return type;
    }
    int GetCarPowerValue () const
    {
        return powerValue;
    }

private:
    string name;
    string type;
    int powerValue;
};



ostream& operator << (ostream& stream, const CarModel& carmodel)
{
    stream << carmodel.GetCarModelName() << ' ' << carmodel.GetCarType()
        << ' ' << carmodel.GetCarPowerValue() << " hp";
    return stream;
}


bool operator < (const CarModel& r, const CarModel& l)
{
    return (r.GetCarModelName() < l.GetCarModelName());
}

class Database
{
public:
    
    void AddCompanyModel (const string& company, const CarModel& carmodel)
    {
        database[company].insert(carmodel);
    }

    int CheckString (const string& sinput) const
    {
        for (const auto& k : database)
        {
            if (k.first == sinput)
            {
                return 1;
            }
            else
            {
                for (const auto& i : k.second)
                {
                    if (i.GetCarType() == sinput)
                    {
                        return 2;
                    }
                    else if (i.GetCarModelName() == sinput)
                    {
                        return 3;
                    }
                }
            }
        }

        return 4;
        
    }

    void PrintAllModels() const
    {
        if (database.empty())
        {
            cout << "No models in database" << endl;
        }
        for (const auto& i : database)
        {
            cout << i.first << ": ";
            unsigned int s = 0;
            for (const auto& k : i.second)
            {
                ++s;
                if (s < i.second.size())
                {
                    cout << k.GetCarModelName() << ", ";
                }
                else if ( s == i.second.size())
                {
                    cout << k.GetCarModelName();
                }
                
            }
            cout << endl;
        }
    }
    
    
    void PrintCompany (const string& companyname) const
    {
        if (database.count(companyname) == 0)
        {
            cout << "No company in database with name: " + companyname << endl;
        }
        else
        {
            for (const auto& k : database)
            {
                if (k.first == companyname)
                {
                    unsigned int s = 0;
                    for (const auto& i : k.second)
                    {
                        
                        ++s;
                        
                        if (s < k.second.size())
                        {
                            cout << i.GetCarModelName() << ", ";
                        }
                        
                        else if( s == k.second.size())
                        {
                            cout << i.GetCarModelName();
                        }
                        
                    }
                    cout << endl;
                }
            }
        }
        
    }

    void PrintType(const string& sinput) const
    {
        vector <string> typebase;
        for (const auto& k : database)
        {
            for (const auto& i : k.second)
            {
                if (i.GetCarType() == sinput)
                {
                    
                    typebase.push_back(i.GetCarModelName());
                    
                }   
            }
        }

        cout << sinput << ": ";
        unsigned int x = 0;
        for (const auto& s : typebase)
        {
            ++x;
            if ( x < typebase.size())
            {
                cout << s << ", ";
            }
            else if ( x == typebase.size())
            {
                cout << s;
            }
            
        }

        cout << endl;

    }

    void PrintCarInformation (const string& sinput) const
    {
        for (const auto& k : database)
        {
            for (const auto& i : k.second)
            {
                if (i.GetCarModelName() == sinput)
                {
                    cout << i.GetCarModelName() << " made by" << k.first << " with " << i.GetCarType() << " type " << " and " << i.GetCarPowerValue() << "hp" << endl;
                }
            }
        }
    }

    bool DeleteCompany (const string& _companyname)
    {
        for (const auto& k : database)
        {
            if (k.first == _companyname)
            {
                database.erase(_companyname);
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;
    }

    int DeleteCarMOdel (const string& _companyname, const string& _carmodel)
    {
        for (const auto& k : database)
        {
            if (k.first == _companyname)
            {
                for (const auto& i : k.second)
                {
                    if (i.GetCarModelName() == _carmodel)
                    {
                        set<CarModel>::iterator it = k.second.find(i.GetCarModelName());
                    }
                    
                }
            }
        }
    }
private:
    map<string, set<CarModel>> database;
};




//void ValidNextCharAndSkip (stringstream& s, const string& carmodel) 
//{
//  if (s.peek() != ' ')
//  {
//      throw logic_error("Wrong format in: " + carmodel);
//  }
//  s.ignore(1);
//}

CarModel ParseCarModel (const string& carmodel, const string& cartype, const int& powerValue)
{
    stringstream car_stream(carmodel);
    stringstream car_type(cartype);
    string name, type;
    car_stream >> name;
    // ValidNextCharAndSkip(car_stream, carmodel);
    car_type >> type;
    // ValidNextCharAndSkip(car_stream, carmodel);
    return { name, type, powerValue };
    
}

int main()
{
    try
    {
        Database base;
        string command;
        while(getline(cin,command))
        {
            stringstream stream(command);

            string operation;
            stream >> operation;

            if (operation == "Add")
            {
                string _companyname, _carName, _carType;
                int _carPowerValue;

                stream >> _companyname >> _carName >> _carType >> _carPowerValue; 

                const CarModel car = ParseCarModel(_carName, _carType, _carPowerValue);
                
                base.AddCompanyModel(_companyname, car);
                
            }
            else if (operation == "Print")
            {
                string sinput;
                stream >> sinput;
                
                if (sinput.empty())
                {
                    base.PrintAllModels();
                }
                else
                {
                    if (base.CheckString(sinput) == 1)
                    {
                        base.PrintCompany(sinput);
                    }
                    else if (base.CheckString(sinput) == 2)
                    {
                        base.PrintType(sinput);
                    }
                    else if (base.CheckString(sinput) == 3)
                    {
                        base.PrintCarInformation(sinput);
                    }
                    else if (base.CheckString(sinput) == 4)
                    {
                        cout << "No such a type or a company in database: " + sinput << endl;
                    }
                }
                
            }
            else if (operation == "Del")
            {
                string _companyname, _carname;
                stream >> _companyname;
                
                if (!stream.eof())
                {
                    stream >> _carname;
                }

                if (_carname.empty())
                {
                    if (base.DeleteCompany(_companyname))
                    {
                        cout << _companyname << " was deleted successfully" << endl;
                    }
                    else
                    {
                        cout << "Company named " << _companyname << " not found" << endl;
                    }
                }
            }
            else if (!operation.empty())
            {
                throw logic_error("Unknown command: " + command);
            }
        }
    } catch (exception& ex) {

        cout << ex.what() << endl;
    }

    return 0;
    
}

更好地了解您的容器!

除了唯一键值和自动排序之外,您可能想要使用 mapset 的一个原因是对数复杂度键检索。你永远不应该遍历它们来查看你是否有特定的密钥。

在你的 DeleteCarModel 中,你不应该使用 for (const auto& k : database) ...。您有两个选择:

if(database.find(_companyname) != database.end())
{
    database[_companyname] ...
}

database.at(_companyname) ...

它们都允许您直接访问底层 set,而第二个在找不到密钥时抛出 out_of_range 异常。我只是建议这样做,因为您已经在早期代码中使用了一些异常处理。

然后你可以使用set.erase删除具体的车型:

if(database.find(_companyname) != database.end())
{
    database[_companyname].erase(_carmodel);
}

database.at(_companyname).erase(_carmodel);

更新:

然而,此解决方案仅在 _carmodel 实际上是 CarModel 类型时才有效,但事实并非如此。 _carmodel这里其实是一个字符串

为了在 map/set 中找到一个值不是键类型的特定键,您首先要定义一对自定义 operator<s:

bool operator<(const string& lhs, const CarModel& rhs)
{ return lhs < rhs.GetCarModelName(); }

bool operator<(const CarModel& lhs, const string& rhs)
{ return lhs.GetCarModelName() < rhs; }

bool operator<(const CarModel& lhs, const CarModel& rhs)
{ return lhs.GetCarModelName() < rhs.GetCarModelName(); }

然后你可以通过指定std::less<>来设置一个Compare::is_transparent标志,以便在创建数据库时进行比较:

map<string, set<CarModel, std::less<>>> database;

现在 set.find 适用于 string:

if(auto company_it = database.find(_companyname); company_it != database.end())
{
    if(auto carmodel_it = company_it->second.find(_carmodel); carmodel_it != company_it->second.end())
    {
        company_it->erase(carmodel_it);
    }
}

或者,如果您使用的是 c++14 或更早版本:

auto company_it = database.find(_companyname);
if(company_it != database.end())
{
    auto carmodel_it = company_it->second.find(_carmodel);
    if(carmodel_it != company_it->second.end())
    {
        company_it->second.erase(carmodel_it);
    }
}