【问题标题】:C++ list remove duplicates stringsC ++列表删除重复字符串
【发布时间】:2011-01-20 15:40:25
【问题描述】:

我在使用列表时遇到了一点问题。

我所拥有的:我正在从聊天框中读取行,其中不时出现新的文本行。 我总是从盒子里取出最后 20 行,然后我想将它们与我之前取出的所有行进行比较。如果发现新行,则将其发送到外部函数,该函数将行分解以进行进一步处理。在我使用数组和向量之前,列表似乎是更好的方法。

我的想法:我有一个名为 usedlines 的列表,其中包含所有旧的 allready 行。 fetchedLines 列表包含从聊天框中获取的最新 20 行。

不,我只是想循环遍历它们以找出获取的行是否包含以前未见过的新行。在循环之后,fetchedlines 中的剩余部分被处理到下一个函数。

问题:当我循环通过这个循环时,我会在一段时间后得到一个错误指针。为什么? 奖励:有没有人有更好的想法来解决这个任务?

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);
  }

}

【问题讨论】:

  • 查看std::setstd::remove_ifstd::set_intersection 以获得更快的解决方案。

标签: c++ list unique


【解决方案1】:

fetchedlines.remove(*f) 的调用使您的迭代器无效。

编辑:

您遇到的问题的一个可能解决方案是只迭代 usedLines 并删除 fetchedlines 中包含的所有元素。

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

//Process all of fetchedLines

【讨论】:

  • 该死,这听起来很聪明!感谢您的想法,我会尝试一下;-)
  • 有比这更快的解决方案,例如 larsmans 建议,但这至少应该解决问题。
  • 好的,它是这样工作的!我仍然有点卡在阵列思维中,所以我会看看 larsmans 的建议。感谢大家朝着正确的方向努力。
【解决方案2】:

您收到错误的原因是 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;
        }
    }
}

(当然不是说这是否是解决问题的好方法)

【讨论】:

    【解决方案3】:

    在迭代列表时,您绝不能修改列表(或几乎任何其他容器)。这是你的直接问题。

    一个更有趣的问题是你为什么要这样做。有没有办法在行上获取序列号,或者可能是时间戳,所以你可以比较它们吗?

    【讨论】:

    • 我想到了这样的事情,但是我读到的行中没有行号或时间戳...重复项不仅删除了“太多”元素,还删除了邪恶的双胞胎......
    • "在迭代列表时,您绝不能修改列表(或几乎任何其他容器)。"我将把这个建议放在我的小蓝皮书中,并附上关于 C++ 的注释。谢谢
    【解决方案4】:

    您正在从fetchedlines 中删除一个元素,同时您正在迭代它。

    这就是你得到一个错误指针的原因。

    【讨论】:

    • 听起来合乎逻辑...所以我必须先循环遍历整个内容并记住以后要删除哪些元素(循环遍历整个内容之后)?!
    • 这不是一种性感的方式。看看 Goz 或 James 的答案......这些更性感。
    【解决方案5】:

    因为 *f 是一个迭代器,指向您刚刚删除的元素。

    尝试以下方法:

    if(*u==*f)
    {
        LISTSTR::iterator t = f;;
    
        f--;
        fetchedlines.remove(*t);
    }
    

    顺便说一句,remove 在列表中搜索与迭代器 f 指向的数据匹配的内容。如果您想简单地摆脱指向您的数据,最好这样做

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

    【讨论】:

      【解决方案6】:

      这可以通过 list::remove_if 和 lambda 表达式来完成。此方法仍然是两个嵌套循环,但它们隐藏在函数调用中。这对于小型列表可能足够快,但不会很好地扩展。如果对数据进行排序或使用有序容器,则速度可能会快得多。

      fetchedLines.remove_if([&](std::string &str)
      {
          return std::find(usedLines.begin(), usedLines.end(), str) != usedLines.end();
      });
      

      【讨论】:

        猜你喜欢
        • 2014-09-16
        • 2014-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-14
        • 2011-12-17
        • 1970-01-01
        • 2016-10-24
        相关资源
        最近更新 更多