Erase Set Elements while Iterating in C++

In this article we will discuss how to erase elements from a set while iterating over it.

Erasing elements from std::set while Iterating

std::set provides a member function erase() that accepts an iterator as an argument and deletes it from the set i.e.

iterator  erase (const_iterator position);

But it makes the passed iterator invalid. From c++11 onward it returns an iterator that points to the element next to last deleted element. We can use this for further iteration.

Let’s see an example,

Suppose we have a set of strings i.e.

// Set of Strings
std::set<std::string> setOfStrs = {"Hi", "Hello", "is", "the", "at", "Hi", "is", "from", "that"};

Now lets remove all string entries from string whose length is greater than 3 i.e.

// Create an iterator pointing to start of set
std::set<std::string>::iterator it = setOfStrs.begin();

// Iterate over the set till end
while(it != setOfStrs.end())
{
	if(it->size() > 3)
	{
		// Remove string from set if length is greater than 3.
		it = setOfStrs.erase(it);
	}
	else
		it++;
}

Complete example is as follows,



    #include <iostream>
    #include <set>
    #include <iterator>
    #include <string>
    #include <vector>
    
    int main()
    {
    // Set of Strings
    std::set<std::string> setOfStrs = {"Hi", "Hello", "is", "the", "at", "Hi", "is", "from", "that"};
    
    	// Printing Set on console
    	std::copy (setOfStrs.begin(), setOfStrs.end(), std::ostream_iterator<std::string>(std::cout, ", "));
    	std::cout<<std::endl;
    
    	// Create an iterator pointing to start of set
    	std::set<std::string>::iterator it = setOfStrs.begin();
    
    	// Iterate over the set till end
    	while(it != setOfStrs.end())
    	{
    		if(it->size() > 3)
    		{
    			// Remove string from set if length is greater than 3.
    			it = setOfStrs.erase(it);
    		}
    		else
    			it++;
    	}
    	// Printing Set on console
    	std::copy (setOfStrs.begin(), setOfStrs.end(), std::ostream_iterator<std::string>(std::cout, ", "));
    	std::cout<<std::endl;
    
    	return 0;
    }
    

    Output:

    Hello, Hi, at, from, is, that, the, 
    Hi, at, is, the,

    Creating generic erase_if for std::set

    Let’s create a generic function that can be used with set, vector or list to remove elements while iterating based on some condition i.e.

    /*
     * Creating a generic function that will erase elements from container
     * while iterating if any given condition matches.
     *
     * It accepts following arguments
     *
     * 1.) Container i.e. set, list or vector
     * 2.) Iterator pointing to start of range
     * 3.) Iterator pointing to end of range
     * 4.) Callback to check if it needs to delete the current element
     *
     * It Iterates over the range and check if element needs to be deleted using passed checker callback.
     * If Yes then it deletes the element
     */
    template <typename S, typename T>
    void erase_if(S & container, T first, T last, std::function<bool (T)> checker)
    {
    	while(first != last)
    	{
    		if(checker(first))
    		{
    			first = container.erase(first);
    		}
    		else
    			first++;
    	}
    
    }

    Now let’s use the above generic function to erase all string from set whose size is greater than 2 i.e.

    // Set Of String
    std::set<std::string> setOfStrs = {"Hi", "Hello", "is", "the", "at", "Hi", "is", "from", "that"};
    
    typedef std::set<std::string>::iterator SetIter ;
    
    // Callback to check if size of string is greater than 2.
    std::function<bool (SetIter)> lambda = [](SetIter it) -> bool {
    							return it->size() > 2;
    							};
    
    // Remove all strings from set whose length is greater than 3.
    erase_if<>(setOfStrs, setOfStrs.begin(), setOfStrs.end(), lambda);
    

    Complete example is as follows,

    #include <iostream>
    #include <set>
    #include <iterator>
    #include <string>
    #include <functional>
    #include <vector>
    
    /*
     * Creating a generic function that will erase elements from container
     * while iterating if any given condition matches.
     *
     * It accepts following arguments
     *
     * 1.) Container i.e. set, list or vector
     * 2.) Iterator pointing to start of range
     * 3.) Iterator pointing to end of range
     * 4.) Callback to check if it needs to delete the current element
     *
     * It Iterates over the range and check if element needs to be deleted using passed checker callback.
     * If Yes then it deletes the element
     */
    template <typename S, typename T>
    void erase_if(S & container, T first, T last, std::function<bool (T)> checker)
    {
    	while(first != last)
    	{
    		if(checker(first))
    		{
    			first = container.erase(first);
    		}
    		else
    			first++;
    	}
    
    }
    int main()
    {
    
    	typedef std::set<std::string>::iterator SetIter ;
    
    	// Set Of String
    	std::set<std::string> setOfStrs = {"Hi", "Hello", "is", "the", "at", "Hi", "is", "from", "that"};
    
    	// Printing Set Contents
    	std::copy(setOfStrs.begin(), setOfStrs.end(), std::ostream_iterator<std::string>(std::cout, ", "));
    	std::cout<<std::endl;
    
    	// Callback to check if size of string is greater than 2.
    	std::function<bool (SetIter)> lambda = [](SetIter it) -> bool {
    											return it->size() > 2;
    										};
    	// Remove all strings from set whose length is greater than 3.
    	erase_if<>(setOfStrs, setOfStrs.begin(), setOfStrs.end(), lambda);
    
    
    	// Printing Set Contents
    	std::copy(setOfStrs.begin(), setOfStrs.end(), std::ostream_iterator<std::string>(std::cout, ", "));
    	std::cout<<std::endl;
    
    	return 0;
    }
    

    Output:

    Hello, Hi, at, from, is, that, the, 
    Hi, at, is, 
    

     

     

    Scroll to Top