C ++查找并擦除多图元素

时间:2012-10-08 11:53:39

标签: c++ indexing iterator multimap erase

我需要添加,存储和删除一些对象,例如Person - Hobby。任何人都可以有几个爱好,几个人可以有相同的爱好。所以,multimap是一个很好的容器,对吗?

在添加一对之前,我需要知道它是否尚未添加。我可以看到here没有标准的类方法可以知道,如果具体对,例如MM中存在Peter-Football。因此,我编写了一个方法,如果该对存在,则返回一个正整数(等于mm.begin()和pair迭代器之间的距离),否则返回-1

然后我需要删除一对。我调用我的find方法,返回一些正整数。我打电话给myMultiMap.erase(pairIndex);,但由于某种原因,该对没有被删除。那是我的问题。显然,erase方法需要iterator,而不是int。问题是:如何将整数转换为迭代器?

谢谢!

更新: 我试过这个c.begin() + int_value,但在这一行上遇到了错误error: no match for ‘operator+’ ....

3 个答案:

答案 0 :(得分:3)

不是我赞成你的方法,但如果intbegin()和有问题的迭代器之间的距离,你可以使用

c.begin() + int_value

std::advance(c.begin(), int_value)

获取迭代器。对于非随机访问迭代器的迭代器,需要第二个版本。

为了您的个人理智(以及程序的速度),我建议您以某种形式直接返回迭代器。

有许多可能的接口可以解决这种或那种方式。我称之为“旧C方式”的是一个out参数:

bool find_stuff(stuff, container::iterator* out_iter) {
 ...
 if(found && out_iter)
   *out_iter = found_iter;
 return found;
}

使用它:

container::iterator the_iter;
if(find_stuff(the_stuff, &the_iter)) ...

if(find_stuff(the_stuff, 0)) // if you don't need the iterator

这不是惯用的C ++,但Linus会很满意。

第二个可能且理论上合理的版本使用boost::optional之类的东西来返回值。这样,您可以返回某个值或不返回任何值。

boost::optional<container::iterator> find_stuff(stuff) {
 ...
 if(found && out_iter)
   return found_iter;
 return boost::none;
}

使用:

boost::optional<container::iterator> found = find_stuff(the_stuff);
if(found) {
  do something with *found, which is the iterator.
}

if(find_stuff(the_stuff)) ...

第三种可能的解决方案是std::set::insert方式,即。返回由标志和值组成的对:

std::pair<bool, container::iterator> find_stuff(stuff) {
 ...
 return std::make_pair(found, found_iter);
}

使用:

std::pair<bool, container::iterator> found = find_stuff(the_stuff);
if(found.first) ...

答案 1 :(得分:2)

考虑将您的mulitmap<Person,Hoobby>更改为set<pair<Person,Hobby> > - 那么您现在就不会遇到任何问题。或者考虑更改为map<Person, set<Hobby> >。这两个选项都不允许插入重复对。

答案 2 :(得分:1)

使用2套(不是多套)一套用于爱好,一套用于人,这两套用作过滤器,因此你不要两次添加同一个人(或hobbie)。这些集合上的插入操作给出了插入元素的迭代器(如果已经插入了元素,则为元素的“右”迭代器)。从插入到hobbies_set和person_set中获得的两个迭代器现在用作多图中的键和值

使用第三组(不是multi_set)作为关系而不是multi_map,可以提供在插入关系之前不需要检查的优点,如果它已经存在则不会再次添加,如果它不存在它将被添加。在两种方式中它都会返回一个迭代器和bool(告诉它是否已经存在或者是否已经添加)

数据结构:

typedef std::set<Hobbie> Hobbies;
typedef std::set<Person> Persons;
typedef std::pair<Hobbies::iterator,bool> HobbiesInsertRes;
typedef std::pair<Persons::iterator,bool> PersonsInsertRes;
struct Relation {
  Hobbies::iterator hobbieIter;
  Persons::iterator personIter;
  // needed operator<(left for the as an exercies for the reader);
};
typedef set<Relation> Relations;

Hobbies hobbies;
Persons persons;
Relations relations;

插入:

HobbiesInsertRes hres = hobbies.insert(Hobbie("foo"));
PersonsInsertRes pres = persons.insert(Person("bar"));
relations.insert(Relation(hres.first, pres.first));
// adds the relation if does not exists, if it allready did exist, well you only paid the same amount of time that you would have if you would to do a check first.

查找

// for a concrete Person-Hobbie lookup use 
relations.find(Relation(Hobbie("foo"),Person("Bar")));

// to find all Hobbies of Person X you will need to do some work.
// the easy way, iterate all elements of relations
std::vector<Hobbie> hobbiesOfX;
Persons::iterator personX = persons.find(Person("bar"));
std::for_each(relations.begin(), relations.end(), [&hobbiesOfBar, personX](Relation r){
  if(r.personIter = personX)
    hobbiesOfX.push_back(r.hobbieIter);
});

// other way to lookup all hobbies of person X
Persons::iterator personX = persons.find(Person("bar"));  
relations.lower_bound(Relation(personX,Hobbies.begin()); 
relations.upper_bound(Relation(personX,Hobbies.end());
// this needs operator< on Relation to be implemented in a way that does ordering on Person first, Hobbie second.