I would like to know if there is an efficient way to remove objects from a container based on values of member fields of the objects. For example, I can do the following using stl::unique with a list of strings:
#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;
}
prints 1001, 81...
Is there a way I can do something similar with the following code, or do I need to perform the comparisons "manually" using operators and iterating through the containers. I couldn't think of a more elegant solution and would like to know if this is possible without writing a lot of code. Any help will be much appreciated!
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;
}
Thanks
Two options to be able to use std::unique
:
Define an operator==
method for Packet
and change the vector<Packet*>
to vector<Packet>
.
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;
}
Keep the vector as vector<Packet*>
and define a method to compare the elements.
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;
}
As an alternative to unique
, you could simply insert the elements into a set
(or unordered_set
in C++11).
Whichever way you decide to go, you'll need to define comparison operators for Packet
. For unique
, you'll need operator==
; for set
you'll need operator<
. For completeness, you should define both, and their counterparts:
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); }
…
};
If you use C++11's unordered_set
, you'll need to go one step further and define a hash function.
EDIT: I just noticed you're storing pointers to Packet
. Why? Just store Packet
directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With