У меня есть список строк, как я могу удалить дублирующее значение в std :: list, например
std::list<std::string> listName;
listName.push_back("Foo");
listName.push_back("Bar");
listName.push_back("Foo");
Затем я хочу удалить дублирующее имя, которое является "Foo". Остальное - это только имя "Бар".
Благодарю!
Если вы хотите только уникальные элементы в 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
Сортируйте список, затем вы можете легко найти дубликаты.
#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;
}
Один из способов сделать это - использовать 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;
}
And remaining is only "Bar" name.