【问题标题】:std::unique and removing duplicates from a container of objectsstd::unique 并从对象容器中删除重复项
【发布时间】:2012-10-11 23:32:35
【问题描述】:

我想知道是否有一种有效的方法可以根据对象成员字段的值从容器中删除对象。例如,我可以使用带有字符串列表的 stl::unique 执行以下操作:

#include<iostream>
#include<list>
#include<string>
#include<algorithm>
using namespace std;

bool stringCompare(const string & l, const string & r)                                                                                   
{                                                                                                                                    
   return (l==r);                                                                                                                         
}

int main()                                                                                                                               
{                                                                                                                                        

  list<string> myStrings;                                                                                                                
  myStrings.push_back("1001");                                                                                                           
  myStrings.push_back("1001");                                                                                                           
  myStrings.push_back("81");                                                                                                             
  myStrings.push_back("1001");                                                                                                           
  myStrings.push_back("81");                                                                                                             

  myStrings.sort();                                                                                                                      
  myStrings.erase(unique(myStrings.begin(), myStrings.end(), stringCompare), myStrings.end());                                           

  list<string>::iterator it;                                                                                                             
  for(it = myStrings.begin(); it != myStrings.end(); ++it)                                                                               
  {                                                                                                                                      
    cout << *it << endl;                                                                                                                 
  }                                                                                                                                      

  return     0;                                                                                                                              
}

打印 1001、81...

有没有办法可以使用以下代码执行类似的操作,或者我是否需要使用运算符“手动”执行比较并遍历容器。我想不出更优雅的解决方案,并且想知道这是否可能在不编写大量代码的情况下实现。任何帮助都感激不尽!

class Packet
{
public:
Packet(string fTime, string rID) : filingTime(fTime), recordID(rID)

  string getFilingTime() {return filingTime;}
  string getRecordId() {return recordID;}

private:
  string filingTime;
  string recordID;

};

int main()
{
vector<Packet*> pkts;
pkts.push_back(new Packet("10:20", "1004"));
pkts.push_back(new Packet("10:20", "1004")); // not unique (duplicate of the line above)
pkts.push_back(new Packet("10:20", "251"));
pkts.push_back(new Packet("10:20", "1006"));

// remove packet from vector if time and ID are the same

return 0;
}

谢谢

【问题讨论】:

  • 为什么会有一个指针向量?一旦你有了一个数据包向量,你需要做的就是添加一个Packet::operator==
  • 这就是我从另一个方法(不是我的代码)传递过来的。我可以改变它,我想事情会更容易......啊哈,我应该想到的。

标签: c++ stl std


【解决方案1】:

两个选项可以使用std::unique

  1. Packet 定义一个operator== 方法并将vector&lt;Packet*&gt; 更改为vector&lt;Packet&gt;

    bool Packet::operator==(const Packet& rhs) const
    {
        if (getFilingTime() != rhs.getFilingTime())
            return false;
        if (getSpid() != rhs.getSpid())
            return false;
        return true;
    }
    
    //etc.
    
    int main()
    {
        vector<Packet> pkts;
        pkts.push_back(Packet("10:20", "1004"));
        pkts.push_back(Packet("10:20", "1004")); // not unique (duplicate of the line above)
        pkts.push_back(Packet("10:20", "251"));
        pkts.push_back(Packet("10:20", "1006"));
    
        // remove packet from vector if time and ID are the same
    
         pkts.erase(unique(pkts.begin(), pkts.end()), pkts.end());                   
    
        return 0;
    }
    
  2. 将向量保持为vector&lt;Packet*&gt;,并定义一个方法来比较元素。

    bool comparePacketPtrs(Packet* lhs, Packet* rhs)
    {
        if (lhs->getFilingTime() != rhs->getFilingTime())
            return false;
        if (lhs->getSpid() != rhs->getSpid())
            return false;
        return true;
    }
    
    //etc.
    
    int main()
    {
        vector<Packet*> pkts;
        pkts.push_back(new Packet("10:20", "1004"));
        pkts.push_back(new Packet("10:20", "1004")); // not unique (duplicate of the line above)
        pkts.push_back(new Packet("10:20", "251"));
        pkts.push_back(new Packet("10:20", "1006"));
    
        // remove packet from vector if time and ID are the same
    
         pkts.erase(unique(pkts.begin(), pkts.end(), comparePacketPtrs), pkts.end());                   
    
        return 0;
    }
    

【讨论】:

  • 是的,不开玩笑。哈哈。谢谢。
  • @GeoffMontee 遇到了同样的问题,并提出了相同的解决方案。但是,在第二种方法中,由于我们有一个动态创建的 Packet 实例的向量(使用 new),我们不需要释放内存吗? pkts.erase(_; _; _;) 从向量中删除元素时会为我们释放它吗?
【解决方案2】:

作为unique 的替代方案,您可以简单地将元素插入set(或C++11 中的unordered_set)。

无论您决定采用哪种方式,都需要为Packet 定义比较运算符。对于unique,您需要operator==;对于set,你需要operator&lt;。为了完整起见,您应该定义两者及其对应项:

class Packet {
    …
    bool operator==(const Packet& p) const {
        return fillingTime == p.fillingTime && recordID == p.recordID;
    }
    bool operator<(const Packet& p) const {
        return fillingTime < p.fillingTime ||
               (fillingTime == p.fillingTime && recordID < p.recordID);
    }
    bool operator!=(const Packet& p) const { return !(*this == p); }
    bool operator> (const Packet& p) const { return p < *this; }
    bool operator>=(const Packet& p) const { return !(*this < p); }
    bool operator<=(const Packet& p) const { return !(p < *this); }
    …
};

如果你使用 C++11 的 unordered_set,你需要更进一步,定义一个哈希函数。

编辑:我刚刚注意到您正在存储指向Packet 的指针。为什么?直接存储Packet即可。

【讨论】:

  • 如果你绝对必须有一个指针向量,你可以将比较函数传递给 unique 和 sort ,它们将接受指针并对底层实例进行操作。注意比较函数的语义分别是“==”和“
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-10
  • 2021-05-12
  • 2016-03-12
  • 2017-06-23
相关资源
最近更新 更多