C ++ список удалить дубликаты строк - PullRequest
5 голосов
/ 20 января 2011

У меня небольшая проблема при использовании списков.

Что у меня есть: я читаю строки из чата, где время от времени появляются новые строки текста. Я всегда беру последние 20 строк из коробки, затем я хочу сравнить их со всеми строками, которые я получил ранее. Если обнаружена новая строка, она отправляется внешней функции, которая разбирает строку для дальнейшей обработки. Раньше я использовал массивы и векторы, но список, кажется, лучший способ сделать это.

Моя идея: у меня есть один список, который называется usedlines, который содержит все старые уже использованные строки. Список fetchedLines содержит последние 20 строк, извлеченных из чата.

Нет, я просто хочу пройти через оба цикла, чтобы выяснить, содержит ли извлеченные строки новую строку, которую раньше не видели. После цикла остатки в выбранных линиях передаются следующей функции.

Проблема: Когда я зацикливаюсь на этом цикле, через некоторое время я получаю плохой указатель Зачем? Бонус: у кого-нибудь есть лучшая идея, чтобы решить эту задачу?

typedef list<string> LISTSTR;
LISTSTR::iterator f;
LISTSTR::iterator u;
LISTSTR fetchedlines;                 
LISTSTR usedLines;                



fetchedlines.insert(fetchedlines.end(), "one");
fetchedlines.push_back("two");
fetchedlines.push_back("three");
fetchedlines.push_back("four");
fetchedlines.push_back("three");

usedLines.push_back("three");
usedLines.push_back("blää");
usedLines.push_back("lumpi");
usedLines.push_back("four");


 for (u =  usedLines.begin(); u != usedLines.end(); u++)
 {
 for (f =  fetchedlines.begin(); f != fetchedlines.end(); f++)
   {
   if(*u==*f)
    fetchedlines.remove(*f);
  }

}

Ответы [ 6 ]

5 голосов
/ 20 января 2011

Вызов fetchedlines.remove(*f) делает ваш итератор недействительным.

EDIT:

Возможное решение проблемы, с которой вы столкнулись, состоит в том, чтобы вместо этого просто повторить usedLines и удалить все содержащиеся в fetchedlines элементы.

for (u = usedLines.begin() u != usedLines.end(); u++)
    fetchedLines.remove(*u);

//Process all of fetchedLines
3 голосов
/ 20 января 2011

Причина, по которой вы получаете ошибку, в том, что fetchedlines.remove (* f) изменяет fetchedlines, и если это был последний элемент, то цикл for слишком сильно увеличивается

Попробуйте что-то вроде этого:*

for (u = userLines.begin (); u != usedLines.end (); ++u)
{
    for (f = fetchedlines.begin (); f != fetchedlines.end ();)
    {
        if (*u == *f)
        {
            f = fetchedlines.erase (f);
        }
        else
        {
            ++f;
        }
    }
}

(это, конечно, не относится к тому, является ли это хорошим способом решения проблемы)

2 голосов
/ 20 января 2011

Вы никогда не должны изменять список (или почти любой другой контейнер) во время итерации по нему.Это ваша непосредственная проблема.

Более интересная проблема заключается в том, почему вы делаете это именно так.Разве нет способа получить последовательные числа в строках или, возможно, временные метки, чтобы вы могли просто сравнить их?

2 голосов
/ 20 января 2011

Вы удаляете элемент из fetchedlines во время итерации по нему.

Вот почему вы получаете неверный указатель.

0 голосов
/ 20 января 2011

Это можно сделать с помощью list::remove_if и лямбда-выражения. Этот метод все еще является двумя вложенными циклами, но они скрыты внутри вызовов функций. Это может быть достаточно быстро для небольших списков, но не очень хорошо масштабируется. Это может быть намного быстрее, если данные будут отсортированы или если вы использовали заказанный контейнер.

fetchedLines.remove_if([&](std::string &str)
{
    return std::find(usedLines.begin(), usedLines.end(), str) != usedLines.end();
});
0 голосов
/ 20 января 2011

Поскольку * f - это итератор, указывающий на элемент, который вы только что удалили.

Попробуйте следующее:

if(*u==*f)
{
    LISTSTR::iterator t = f;;

    f--;
    fetchedlines.remove(*t);
}

В качестве удаления в стороне выполняется поиск в списке того, что соответствует данным, указанным итератором f. Если вы хотите просто избавиться от данных, на которые вы указали, лучше сделать

f = fetchedlines.erase( f );
f--;
...