Traversing multiset from lowerbound

80 Views Asked by At

I want to start with a lower_bound iterator of my target value in a multiset, then delete all its occurrences and continue to move onto next values of the same multiset , I am doing like ...

 multiset<int>s={....};
 auto it=s.lower_bound(target); 
 
 while(it!=s.end()){
  if(s.find(target)!=s.end())
    it=s.erase(target);
  else it++;
}

But its giving me error...

Line 36: Char 12: error: no viable overloaded '='
        it4=x.erase(99);
        ~~~^~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_tree.h:326:12: note: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'std::set<int, std::less<int>, std::allocator<int>>::size_type' (aka 'unsigned long') to 'const std::_Rb_tree_const_iterator<int>' for 1st argument
    struct _Rb_tree_const_iteratorrgument

Is there any difference in iterators s.lower_bound(target) and s.erase(target) ? I specifically need to keep traverse in this way as I know another way to keep finding and deleting the target till it can no more be found in set.

1

There are 1 best solutions below

5
Jerry Coffin On

A std::set can only have a single instance of any value, so calling erase once removes all possible instances of that value. No need to call lower_bound first, or anything like that. For example:

int main(){
    std::set<int> x = { 1, 2, 3, 4, 5};

    x.erase(2);
    for (auto const &p : x)
        std::cout << p << " ";    
}

Produces:

1 3 4 5

Live on Coliru

If you want to store multiple copies of the same value, that would be an std::multiset instead. In this case, if you want to remove all copies of a particular value, the most straightforward way is probably to use std::equal_range:

#include <set>
#include <iostream>

int main() { 
    std::multiset<int> s { 1, 2, 3, 4 ,4, 5, 2, 1, 3};
    auto p = s.equal_range(2);

    s.erase(p.first, p.second);

    for (auto const & v : s)
        std::cout << v << " ";
    std::cout << "\n";
}

Result:

1 1 3 3 4 4 5 

Live on coliru

But you might also note that we still don't really need to specify a range to traverse for this case. We can still just specify the value to be erased, and all instances of it will be erased:

#include <set>
#include <iostream>

int main() { 
    std::multiset<int> s { 1, 2, 3, 4 ,4, 5, 2, 1, 3};

    s.erase(2);

    for (auto const & v : s)
        std::cout << v << " ";
    std::cout << "\n";
}

[Same result as above]

Live on Coliru

equal_range would be useful if (for example) we wanted to erase all but one of the instances of that value in the set. In this case, we could (for example) call equal_range, and either increment its .first or decrement its .second, then call erase, erasing all but one of that value.