Remove elements from a set in C++
1. Remove a single element from a set in C++.
2. Conditionally remove elements from a set in C++ which satisfy a predicate.
1. Deleting a single element
Deleting a single element from the set container is very simple in C++. The idea is to pass the given element to the set::erase function, which erases it from the set.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream> #include <unordered_set> int main() { std::unordered_set<char> s = { 'a', 'b', 'c', 'd' }; int key = 'd'; s.erase(key); for (char const &c: s) { std::cout << c << ' '; } return 0; } |
Output:
c b a
2. Deleting all elements that satisfy a predicate
We can even conditionally remove elements from a set that satisfies a predicate. The idea is to use iterators to iterate the set and call the unordered_set::erase function if the current element matches the condition. Note that calling the erase() function while iterating requires special attention since it invalidates the iterator. We can handle this in several ways:
1. In C++11 and above, erase() returns an iterator to the next element or to the unordered_set::end if the last element is removed. The idea is to use the return value of erase() for setting the iterator to the next element, as shown below:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <iostream> #include <unordered_set> #include <cctype> int main() { std::unordered_set<char> s = { 'A', 'b', 'c', 'D' }; auto it = s.begin(); while (it != s.end()) { if (isupper(*it)) { it = s.erase(it); } else { ++it; } } for (char const &c: s) { std::cout << c << ' '; } return 0; } |
Output:
c b
2. In C++98/03, erase() does not return an iterator to the next element. The workaround is to increment the iterator after it is passed to the erase() but before erase() is executed. This will pass a copy of the iterator to the erase() function, and the iterator will not be invalidated since it is already incremented before erase() is called.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <iostream> #include <unordered_set> #include <cctype> int main() { std::unordered_set<char> s = { 'A', 'b', 'c', 'D' }; for (auto it = s.begin(); it != s.end();) { if (isupper(*it)) { s.erase(it++); } else { it++; } } for (char const &c: s) { std::cout << c << ' '; } return 0; } |
Output:
c b
3. Another good alternative is to call the erase() function on a duplicate of the current iterator after advancing the iterator to the next element. This works exactly like the previous approach, where an implicit copy of the iterator is passed to the function.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <iostream> #include <unordered_set> #include <cctype> int main() { std::unordered_set<char> s = { 'A', 'b', 'c', 'D' }; auto it = s.cbegin(); while (it != s.cend()) { auto curr = it++; if (isupper(*curr)) { s.erase(curr); } } for (char const &c: s) { std::cout << c << ' '; } return 0; } |
Output:
c b
4. Another solution is to iterate the set and build up a ‘to-be-removed-list’ of iterators to the elements that satisfy the predicate. Then we loop through that list and call set::erase on each iterator.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <iostream> #include <unordered_set> #include <list> #include <cctype> int main() { std::unordered_set<char> s = { 'A', 'b', 'c', 'D' }; std::list<std::unordered_set<char>::const_iterator> iterators; for (auto it = s.cbegin(); it != s.cend(); it++) { if (isupper(*it)) { iterators.push_back(it); } } for (auto const &i: iterators) { s.erase(i); } for (char const &c: s) { std::cout << c << ' '; } return 0; } |
Output:
c b
That’s all about removing elements from a set in C++.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)