Search code examples
c++algorithmfunction-definitionerase-remove-idiomforward-list

Delete the selected item in forward_list C++


I need to somehow remove an element in a list if it is already in another list. I created a function but it doesn't work. Tell me how to fix it. thank you very much.

void compare(forward_list<string> list_1, forward_list<string> list_2) {

    auto prev = list_1.before_begin();

    for (int i = 0; i < Size(list_1); i++) {

        auto l_front = list_1.begin();
        advance(l_front, i);
        
        for (int j = 0; j < Size(list_2); j++) {

            auto l_front_2 = list_2.begin();
            advance(l_front_2, j);
            if (*l_front == *l_front_2)
            {
                l_front_2 = list_2.erase_after(l_front);
            }

        }
    }
}

Solution

  • It seems you are trying to remove elements from list_2 that are found in list_1. But in this statement

    l_front_2 = list_2.erase_after(l_front);
    

    you are using the iterator l_front from list_1 that does not make a sense.

    Also if an element in list_2 is removed then due to the expression j++ in the for loop

    for (int j = 0; j < Size(list_2); j++) {
    

    the next element in the list will be skipped.

    A straightforward approach can look for example the following way as it is shown in the demonstration program below.

    #include <iostream>
    #include <string>
    #include <forward_list>
    #include <iterator>
    #include <algorithm>
    
    void make_unique( std::forward_list<std::string> &list_1,
        const std::forward_list<std::string> &list_2 )
    {
        for ( auto current = std::begin( list_1 ); current != std::end( list_1 ); )
        {
            if (std::find( std::begin( list_2 ), std::end( list_2 ), *current ) != std::end( list_2 ))
            {
                std::string s( *current );
                list_1.remove( s );
                current = std::begin( list_1 );
            }
            else
            {
                std::advance( current, 1 );
            }
        }
    }
    
    int main()
    {
        std::forward_list<std::string> list_1 = { "A", "B", "A", "C", "D", "B", "E" };
        std::forward_list<std::string> list_2 = { "A", "B" };
    
        for (const auto &s : list_1)
        {
            std::cout << s << ' ';
        }
        std::cout << '\n';
    
        make_unique( list_1, list_2 );
    
        for (const auto &s : list_1)
        {
            std::cout << s << ' ';
        }
        std::cout << '\n';
    }
    

    The program output is

    A B A C D B E
    C D E
    

    A much more simple function definition can be if to use the method remove_if or the general function std::erase_if introduced in the C++ 20 Standard. For example

    void make_unique( std::forward_list<std::string> &list_1,
        const std::forward_list<std::string> &list_2 )
    {
        auto found = [&list_2]( const auto &s )
        {
            return std::find( std::begin( list_2 ), std::end( list_2 ), s ) != std::end( list_2 );
        };
    
        list_1.remove_if( found );
    }
    

    Or if the compiler supports C++ 20 then

    void make_unique( std::forward_list<std::string> &list_1,
        const std::forward_list<std::string> &list_2 )
    {
        auto found = [&list_2]( const auto &s )
        {
            return std::find( std::begin( list_2 ), std::end( list_2 ), s ) != std::end( list_2 );
        };
    
        std::erase_if( list_1, found );
    }
    

    The both presented functions remove elements in list_1 that are found in list_2.