Удалить дубликаты в std :: list [closed]

0

У меня есть список строк, как я могу удалить дублирующее значение в std :: list, например

std::list<std::string> listName;

listName.push_back("Foo");
listName.push_back("Bar");
listName.push_back("Foo");

Затем я хочу удалить дублирующее имя, которое является "Foo". Остальное - это только имя "Бар".

Благодарю!

Теги:

3 ответа

2

Если вы хотите только уникальные элементы в listName вы можете сделать:

listName.sort();  
listName.unique();

listName должно оставаться: "Foo", "Bar"

Если вы хотите избавиться от всех элементов, у вас есть дубликат, вы можете использовать std::list::sort для сортировки элементов, а затем использовать std::adjacent_find для поиска повторяющихся элементов.

listName.sort();   

std::list<std::string>::iterator ab = std::adjacent_find(listName.begin(), listName.end());
if (ab != listName.end())  // if duplicate elements are found
{
    std::list<std::string>::iterator ae = std::upper_bound(listName.begin(), listName.end(), *ab);  // try to locate last occurrence 
    if (std::distance(ab, ae) > 1)
    {
        listName.erase(ab, ae); // remove all dup elements
    }
}

listName остается: "Bar"

См. Здесь fore more std::list inerface

  • 0
    ОП указал, что остается только «Бар». Это также будет иметь "Foo".
  • 0
    Я только что применил этот подход, и это было неправильно, так как ОП хочет, And remaining is only "Bar" name.
Показать ещё 5 комментариев
0

Сортируйте список, затем вы можете легко найти дубликаты.

#include <list>
#include <iostream>
#include <algorithm>

int main()
{
    std::list<std::string> listName = {"Foo", "Bar", "Foo", "Foobar"};

    listName.sort();

    for(auto i = listName.begin(); i != listName.end(); )
    {
        auto range = std::equal_range(i, listName.end(), *i);

        if(std::next(range.first) != range.second)
            i = listName.erase(range.first, range.second);
        else ++i;
    }

    for(auto const& e : listName) std::cout << e << ", ";
}

Самая короткая версия, которую я мог бы придумать, но повторяется дважды над каждым элементом, который нужно удалить (один раз в equal_range и один раз во время erase).

Альтернативно, повторяя один раз над каждым элементом:

    listName.sort();

    for(auto i = listName.begin(); i != listName.end(); )
    {
        auto j = std::next(i);
        bool duplicate = false;

        while(j != listName.end() && *j == *i)
        {
            duplicate = true;
            j = listName.erase(j);
        }

        if(duplicate) i = listName.erase(i);

        i = j;
    }

Как упражнение, перемещение duplicate = true из цикла:

    listName.sort();

    for(auto i = listName.begin(); i != listName.end(); )
    {
        auto j = std::next(i);
        bool duplicate = (j != listName.end() && *j == *i);

        if(duplicate)
        {
            do
            {
                j = listName.erase(j);
            }while(j != listName.end() && *j == *i);

            listName.erase(i);
        }

        i = j;
    }
0

Один из способов сделать это - использовать std::map вместо list. Карта будет хранить строки и подсчитывать, сколько раз они происходят. Единственное реальное изменение вашего кода - вам нужно использовать ++ вместо push_back чтобы поместить строку на карту;

std::map<std::string, int> listName;
++listName["Foo"];
++listName["Bar"];
++listName["Foo"];

Затем для удаления записей с числом больше 1:

for (auto it = listName.begin(); it != listName.end(); )
{
    if (it->second > 1)
        listName.erase(it++);
    else
        ++it;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню