Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove values from a QMap?

Tags:

c++

iterator

qt

Suppose I want to remove items according to some criterium. Let's say:

QMap<int, int> map;

and I want to remove all the items where value is an odd number. If I use an iterator:

for (auto it = map.begin(); it != map.end(); ++it)
    if (it.value() % 2 == 1)
        map.remove(it.key());

This code is probably wrong, since the call of

map.remove(it.key()) 

invalidates the iterator. How can I do this without reseting the iterator after each removal?

like image 360
Martin Drozdik Avatar asked Jul 27 '12 14:07

Martin Drozdik


2 Answers

Use QMap::erase instead, which returns an iterator to the element following the one you just erased:

for (auto it = map.begin(); it != map.end();)
    if (it.value() % 2 == 1)
        it = map.erase(it);
    else
        ++it;

Another way is to use the postfix increment operator on the iterator:

for (auto it = map.begin(); it != map.end();)
    if (it.value() % 2 == 1)
        map.erase(it++);
    else
        ++it;

Yet another way (and probably less efficient) is to use the STL remove_copy_if algorithm, followed by swap:

bool valueIsOdd(int value) {return value % 2 == 1;}

QMap<int,int> b;
std::remove_copy_if(a.begin(), a.end(),
                    std::inserter(b, b.end()),
                    &valueIsOdd);
a.swap(b);

I cannot test the last example at the moment.

like image 132
Emile Cormier Avatar answered Oct 21 '22 13:10

Emile Cormier


You would be better off using the more STL-like erase function:

  • It takes an iterator as an argument, and so doesn't waste time searching for the element by its key when you already know where it is;
  • It returns an iterator to the next element, so you can carry on iterating afterwards.

Using this, you can implement your loop correctly as:

for (auto it = map.begin(); it != map.end(); /* don't increment here */) {
    if (it.value() % 2 == 1) {
        it = map.erase(it);
    } else {
        ++it;
    }
}

I think you could get the same result from map.remove((it++).key()), but that would be both slower and messier than erase.

like image 40
Mike Seymour Avatar answered Oct 21 '22 12:10

Mike Seymour