【问题标题】:How can I remove duplicate values from a list in c++? [closed]如何从 C++ 中的列表中删除重复值? [关闭]
【发布时间】:2011-06-20 03:14:38
【问题描述】:

我是 C++ 新手,遇到了一个问题。我正在使用列表来存储字符串值。 现在我想从该字符串中删除重复的值。谁能告诉我这是怎么做的。

任何示例代码将不胜感激。

【问题讨论】:

  • 您想从字符串或列表中删除重复项?你尝试过什么吗?
  • 这个问题的答案是具有重复值的列表的一个很好的例子:)
  • 如果可能,更改代码以防止在生成列表时插入重复值。为此,您可能会考虑切换到另一个容器,例如 std::set

标签: c++


【解决方案1】:

使用sort,后跟unique

【讨论】:

  • 哈哈!我显然需要更多地阅读参考资料。我什至不知道那里有。
  • @Noah:老实说,我通过谷歌搜索<algorithm>中的全局std::unique意识到了这些成员函数的存在。
  • @Noah:问题是,你什么时候真正使用list ;)?
  • @MatthieuM.:当您需要切片和拼接,或者需要在任何地方插入/删除而不会使任何其他迭代器失效时。 :)
  • @Fred:这实际上是修辞;)我认为迭代器失效无论如何是最强的一点,但我通常使用小型(~5~20)数据集,所以我可以很容易地拼接向量。
【解决方案2】:

如果您有 std::list,您可以使用以下命令删除重复项:

yourlist.sort();
yourlist.unique();

【讨论】:

    【解决方案3】:

    使用 unique()。

    但是 first sort() 列表,或者 unique 不会做你所期望的。

    【讨论】:

      【解决方案4】:

      如果列表已排序,请使用其独特的方法。

      如果列表未排序(并且您不想对其进行排序):

      set<string> found;
      for (list<string>::iterator x = the_list.begin(); x != the_list.end();) {
        if (!found.insert(*x).second) {
          x = the_list.erase(x);
        }
        else {
          ++x;
        }
      }
      

      为了避免将字符串复制到集合中:

      struct less {
        template<class T>
        bool operator()(T &a, T &b) {
          return std::less<T>()(a, b);
        }
      };
      struct deref_less {
        template<class T>
        bool operator()(T a, T b) {
          return less()(*a, *b);
        }
      };
      
      void remove_unsorted_dupes(list<string> &the_list) {
        set<list<string>::iterator, deref_less> found;
        for (list<string>::iterator x = the_list.begin(); x != the_list.end();) {
          if (!found.insert(x).second) {
            x = the_list.erase(x);
          }
          else {
            ++x;
          }
        }
      }
      

      【讨论】:

      • +1 表示不破坏现有订单的示例
      • 这个deref_less比较器有通用名称吗?我自己一直在使用一个,不得不考虑如何命名它:S
      • @7vies:Deref_less 对我来说很有意义:deref 然后 (std::)less。您可以(并且可能应该)将其编写为实际使用 std::less:return std::less&lt;decltype(*a)&gt;(*a, *b);
      • decltype 的有趣用法,一定要记住!
      • @Xeo:这是 decltype 的全部目的。 :) 但它只是 0x。在可移植的 C++03 中,我会写 struct my_less { template&lt;class T&gt; operator()(T &amp;a, T &amp;b) { return std::less&lt;T&gt;()(a, b); } }; struct deref_less { template&lt;class T&gt; bool operator()(T a, T b) { return my_less()(*a, *b); } }; 以避免编译器特定的 pre-0x 等价于 decltype。 (我还错过了评论中的一组括号。)
      【解决方案5】:

      解决方案 1:

      struct already_found
      {
        std::set<std::string> & theSet;
      
        bool operator()(const std::string& s) const
        {
           return !theSet.insert(s).second;
        }
      };
      
      std::set<std::string> theSet;
      the_list.remove_if( the_list.begin(), the_list.end(), already_found(theSet) );
      

      使用 shared_ptr 的解决方案 2

      struct already_found
      {
        boost::shared_ptr<std::set<std::string> > theSet;
        already_found() : theSet( new boost::shared_ptr<std::set<std::string> > )
        {
        }
      
        bool operator()(const std::string& s) const
        {
           return !theSet->insert(s).second;
        }
      };
      
      the_list.remove_if( the_list.begin(), the_list.end(), already_found(theSet) );
      

      这些都有必须复制所有字符串的缺点。您可以通过存储指向字符串的指针并将它们与自定义比较进行比较来稍微优化它。

      【讨论】:

      • Already_found::op() 是 const,但它修改了 theSet。
      • @Fred Nurk 允许修改它。在一种情况下,它是一个参考。在另一个中,它位于 shared_ptr 中。在任何一种情况下,const 都不会传播给它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2011-02-14
      • 2018-05-16
      • 2012-05-19
      相关资源
      最近更新 更多