I need FindIngredient
to return a const Ingredient &
when searching by Ingredient.name
. I need to used unordered_set
. So I think I need 2 of them one to contain the objects and another one just to contain the string attributes name
in order to search by string.
Is my approach ok or can I achieve it using only unordered_set<Ingredient> ingredients
?
Following with my approach what how do I return in FindIngredient
function? I want to return the object in ingredients
whose attribute name is the one found searching in ingredientsByName
class Ingredient {
public:
string Name;
int Price;
string Description;
};
class Pizzeria {
unordered_set<string> ingredientsByName;
unordered_set<Ingredient> ingredients;
public:
void AddIngredient(const string &name, const string &description, const int &price)
{
if(ingredientsByName.find(name) == ingredients.end())
{
throw "Ingredient already inserted";
}
else
{
Ingredient ingredient;
ingredient.Name = name;
ingredient.Price = price;
ingredient.Description = description;
ingredients.insert(ingredient);
ingredientsByName.insert(ingredient.Name);
ingredients.insert(ingredient);
}
}
const Ingredient &FindIngredient(const string &name) const
{
if(ingredientsByName.find(name) == ingredients.end())
{
throw "Ingredient not found";
}
else
{
return // how Do I return the corresponding Ingredient ???
}
}
}
If you don't mind slower algorithm of search (O(N)
time) then you can do a simple loop:
for (auto it = ingredients.begin(); it != ingredients.end(); ++it)
if (it->Name == name)
return *it; // Return found ingredient.
throw "Ingredient not found";
Loop above can be made even shorter:
for (auto const & e: ingredients)
if (e.Name == name)
return e; // Return found ingredient.
throw "Ingredient not found";
If you want fast algorithm of search (O(Log N)
time) then instead of set you may use std::unordered_map, i.e.:
unordered_map<string, Ingredient> ingredientsByName;
adding to map:
ingredientsByName[ingredient.Name] = ingredient;
then search in it:
auto it = ingredientsByName.find(name);
if (it == ingredientsByName.end())
throw "Ingredient not found";
return it->second; // Returns found ingredient.
If you need sorted order of elements (by key) then you can use std::map instead of std::unordered_map, map is always sorted by key (but 2-5 times slower in search and inserting for thousands of elements), while unordered_map is always unsorted (but 2-5 times faster in search and inserting).
If you want to store ingredients separately then you may use std::shared_ptr:
unordered_map<string, shared_ptr<Ingredient>> ingredientsByName;
vector<shared_ptr<Ingredient>> ingredients;
// Adding element:
shared_ptr<Ingredient> ingredient = make_shared<Ingredient>();
ingredient->Name = "abc";
// Also fill other fields.
ingredients.push_back(ingredient);
ingredientsByName[ingredient->Name] = ingredient;
// Search:
auto it = ingredientsByName.find(name);
if (it == ingredientsByName.end())
throw "Ingredient not found";
return *it->second; // Returns found ingredient.