I have declared a structure like:
struct data{
vector<string> att;
string ds;
};
Now a set to store unique data from multiple data element
set<data> s;
based on different vector<string> att
and string ds
How to do this?
I have declared a structure like:
struct data{
vector<string> att;
string ds;
};
Now a set to store unique data from multiple data element
set<data> s;
based on different vector<string> att
and string ds
How to do this?
Without knowing anything about how you want your structure to be compared, you could try the following:
struct data
{
vector<string> att;
string ds;
friend bool operator < (const data& lhs, const data& rhs)
{
if (std::lexicographical_compare(lhs.att.begin(), lhs.att.end(), rhs.att.begin(), rhs.att.end()))
{
return true;
}
else if (std::lexicographical_compare(rhs.att.begin(), rhs.att.end(), lhs.att.begin(), lhs.att.end()))
{
return false;
}
else
{
return lhs.ds < rhs.ds;
}
}
};
I'm not happy with this solution because it performs the lexicographical comparison twice, which is inefficient. Hopefully someone will come along with a better solution.
The basic idea is, for each member, compare left < right. If true, return true, otherwise compare right < left. If true, return false. Otherwise, continue to the next member.
Note: you can read more about the trick I'm using to compare things (std::tie
) in Implementing comparison operators via 'tuple' and 'tie', a good idea?
std::string
and std::vector
already have operator<
defined: for strings and for vectors. So we can use them with std::tie
to create a temporary std::tuple
(it just uses references to the data members, it doesn't create any copies, so it's efficient) for comparison.
operator<
std::set
needs to compare its objects so it knows what's unique and how to sort things. It will do this by using operator<
by default (via std::less
), so if you provide that operator for your class it will use it. Like so:
struct data{
vector<string> att;
string ds;
operator<(const data& other) {
// Be sure to #include <tuple> for std::tie
return std::tie(att, ds) < std::tie(other.att, ds);
// If you don't want to (or can't) use std::tie, you can do this:
// return att < other.att || (att == other.att && ds < other.ds);
}
};
std::set<data> my_set; // Now it works.
This will use the Compare
functor to compare two data
objects (instead of operator<
, so we don't need to define it):
struct Compare {
bool operator()(const data& left, const data& right) const {
return std::tie(left.att, left.ds) < std::tie(right.att, right.ds);
// Again, if you don't want to (or can't) use std::tie, you can do this:
// return left.att < right.att || (left.att == right.att && left.ds < right.ds);
}
};
std::set<data, Compare> my_set; // Now it works.