如何删除 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;
}
更好地了解您的容器!
除了唯一键值和自动排序之外,您可能想要使用 map
或 set
的一个原因是对数复杂度键检索。你永远不应该遍历它们来查看你是否有特定的密钥。
在你的 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);
}
}
我有一个 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;
}
更好地了解您的容器!
除了唯一键值和自动排序之外,您可能想要使用 map
或 set
的一个原因是对数复杂度键检索。你永远不应该遍历它们来查看你是否有特定的密钥。
在你的 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);
}
}