Reputation: 11
As title says, I would like to know what's the most efficient way to remove an element from a list inside a map that meets certain conditions(name and date). Here's the function I provided:
void Register::DeleteActivity(const Date &f,const std::string &a) {
auto it = Registro.find(f);
if(it != Registro.end()) {
if(it->second.empty()) {
std::cout <<"Error"<<std::endl;
} else {
for(auto ip = it->second.begin(); ip != it->second.end();) {
if(ip->getName() == a && ip->getStartdate() == f){
ip->printInfo();
it->second.erase(ip);
} else {
ip++;
}
}
}
} else {
std::cout<< "DeleteActivity::day not found"<<std::endl;
}
}
And here is the full class:
class Register {
private:
map<Date,std::list<Activity>> Registro;
public:
Register(){};
void addActivity(Date &z, Activity &n);
void editActivity(const Date &a, const std::string &c, Date k, const std::string newname);
void DeleteActivity(const Date &f, const std::string &a);
}
Upvotes: 1
Views: 140
Reputation: 484
your code has an segmentation fault as erase invalidates the iterator but returns an iterator to the next element. It should be:
ip = it->second.erase(ip);
A pre-increment is also more efficient than post increment, as the original value has not to be stored and the iterator copied:
++ip;
Otherwise, if you do not have duplicates, I'd use std::set instead of std::list, which should as well be more performant (log instead of linear).
#include <iostream>
#include <map>
#include <set>
std::map<const int, std::set<int>> map_set({{0, {1, 2, 3, 4}},
{1, {10, 20, 30, 40}},
{2, {100, 200, 300, 400}},
{3, {}}});
void delete_from_map_set(const int map_index, int value) {
const auto & map_it = map_set.find(map_index);
if(map_it != map_set.end()) {
map_it->second.erase(value);
}
}
void print_map_set() {
for(auto & map_it : map_set) {
std::cout << map_it.first << ": [";
for(auto & list_it : map_it.second) {
std::cout << list_it << ", ";
}
std::cout << "]" << std::endl;
}
}
int main(int argc, char * argv[]) {
print_map_set();
delete_from_map_set(0, 1);
print_map_set();
return 0;
}
Upvotes: 0
Reputation: 66459
There's a bug: you need ip = it->second.erase(ip);
.
erase
invalidates the iterator and returns an iterator to the next element.
But you can get rid of the loop and let the list do the work:
else {
it->second.remove_if([&f, &a](const Activity& act)
{ return act.getName() == a
&& act.getStartdate() == f; });
}
Upvotes: 2