I've been learning c++. I am stuck with this problem.
I have set that contains a custom struct that contains two long int's a & b. I have a custom comparer struct that compares the numbers and returns true if either a or b is different.
typedef long int li;
struct number {
number(li a1,li b1): a(a1), b(b1) {}
li a, b;
};
struct compare {
bool operator() (const number &lhs, const number& rhs) const{
return lhs.a != rhs.a || lhs.b != rhs.b;
}
};
int main() {
set<number, compare> nums;
nums.insert(number(1, 2));
nums.insert(number(1, 1));
nums.insert(number(2, 1));
nums.insert(number(1, 2));
for (auto &i : nums) {
cout << i.a << " " << i.b << endl;
}
return 0;
}
The output here is
1 2
2 1
1 1
1 2
It has two entries of 1 2. Any clarification would be appreciated.
Your comparison function should return whether some element is smaller than another, not whether or not they are equal. (More formally, it must define a "Strict weak ordering" on the elements of your set.)
Use something like
struct compare {
bool operator() (const number &lhs, const number& rhs) const{
return std::tie(lhs.a, lhs.b) < std::tie(rhs.a, rhs.b);
}
};
If you don't care about ordering, you may want to define a suitable hash function for your type and use std::unordered_set.
To avoid future problems like this, make sure to read the docs. They clearly explain what your comparison function is supposed to do.
For reference: std::tie as used above constructs tuples of references to its arguments which can then be compared lexicographically with <. This is an easy, generic and fast way to build some ordering for collections of less-than-comparable stuff.
Your comparison function needs to meet strict/weak ordering requirements.
(I actually prefer the answer using std::tie, but this may be more illustrative for newcomers)
bool compare(const number& lhs, const number& rhs)
{
if(lhs.a < rhs.a)
return true;
else if(lhs.a > rhs.a)
return false;
else
return lhs.b < rhs.b;
}
Related
As the title suggests am trying to implement comparison functor for my defined structure. Here is the sample snippet
#include<set>
struct testData
{
char * data;
int size;
};
class compare
{
public:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
return memcmp(lhs.data, rhs.data, lhs.size<rhs.size?lhs.size:rhs.size) < 0;
}
};
int main()
{
std::set<testData,compare>S;
....
return 0;
}
Issue in the comparison function is since am taking lesser size,this
case fails
suppose there is already this data present {"test",4},and i am trying
to find {"test1",5}.it will say as matched.How can i modify comparison
to overcome this?
Update:
changed to this
class compare
{
public:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
if (lhs.size == rhs.size)
return memcmp(lhs.data, rhs.data, lhs.size) < 0;
return lhs.size < rhs.size;
}
};
will this work?
You'd use std::lexicographical_compare.
Lexicographical comparison is a operation with the following properties:
Two ranges are compared element by element.
The first mismatching element defines which range is lexicographically less or greater than the other.
If one range is a prefix of another, the shorter range is lexicographically less than the other.
If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
An empty range is lexicographically less than any non-empty range.
Two empty ranges are lexicographically equal.
class compare
{
public:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
return std::lexicographical_compare(lhs.data, lhs.data + lhs.size, rhs.data, rhs.data + rhs.size);
}
};
the reason it failes is because you compare only the length of the smaller string.
In your example only the "test" part of "test1" will be compared.
You can try this:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
int ret = memcmp(lhs.data, rhs.data, lhs.size<rhs.size?lhs.size:rhs.size);
return ret == 0 ? lhs.size < rhs.size : ret < 0 ;
}
This question already has an answer here:
Ordered sort in STL containers
(1 answer)
Closed 9 years ago.
I want to use the stl sort algorithm to sort some numbers, but i also want to remember their initial position.
I have a data structure like this:
struct Numbers {
int position;
int value;
};
I have created a vector of Numbers like this:
vector<Numbers> a;
How to use the stl sort algorithm, such that i sort the data structures based on the value?
You can use a functor too :
struct comp {
bool operator()(const Numbers &lhs, const Numbers& rhs) const{
lhs.value < rhs.value;
}
};
std::sort(a.begin(),a.end(), comp());
With C++11, you can use a lambda function :
std::sort( a.begin() , a.end() ,
[](const Numbers& lhs , const Numbers& rhs)
{ return lhs.value < rhs.value; }
);
You'll need to overload the "<" operator, like so:
bool Numbers::operator<(Numbers temp)
{
return value < temp.value;
}
Use std::sort and provide a custom comparator (template arg Compare)
#include <algorithm>
#include <vector>
//...
std::vector<Numbers> a;
//fill the vector a and set Numbers::position of each element accordingly...
struct {
bool operator()(const Numbers& a,const Numbers& b)const
{
return a.value < b.value;
}
} my_comparator;
std::sort(a.begin(),a.end(),my_comparator);
//...
i searched a lot here and on other sites as well but i have not found something satisfying.
what i need is quite simple task - substantially to construct ORDER BY operator in c++. this means i have struct with a number of various data type members and i need a comparator for it with members and orderings configurable. here is my pseudocode idea:
comparator.add(&MyStruct::member1, std::less);
comparator.add(&MyStruct::member2, std::greater);
std::sort(my_vector.begin(), my_vector.end(), comparator);
and i get data sorted by member1 and if it is equal member2 decides, and so on.
i am not too good in stl and templates, but i can read and decipher some code and found this as very appropriate solution: https://stackoverflow.com/a/11167563
unfortunately in my work i have to use c++ builder with faulty 32bit compiler that refuses to compile this correct code. it does support almost nothing from c++11, it has boost 1.39 available.
does someone have any solution that could work for me with my resources available? thank you in advance
EDIT:
i got very specialised solutions with hard-written comparison operators which i am aware of and which do not work here too good. i missed this in my question. my struct has at least 15 members and as i wrote, i need to often change individual sort directions for members/columns (asc, desc). too, i need to often change set of sorted members, just like in order by operator in sql, for example. also i cannot use something like stable_sort as i am just writing comparator for something like OnCompare event of some class.
It's not too difficult. First, consider the "canonical"
ordering relationship:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
return lhs.a < rhs.a
|| ( !(rhs.a < lhs.a) && lsh.b < rhs.b )
|| ( !(rhs.a < lhs.a) && !(rhs.b < lhs.b) && lhs.c < rhs .c )
|| ...
}
};
Obviously, no one would actually write something like this, but
it corresponds exactly to the formal definition of what is
needed.
Of course, if we can imagine the data members as an array, we
could rewrite this as a loop, taking advantage of the previously
established !(rhs[i-1] < lsh[i-1] in each case:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
int i = 0;
while ( i != N && !(lhs[i] < rhs[i]) && !(rhs[i] < lhs[i]) ) {
++ i;
}
return i != N && lhs[i] < rhs[i];
}
};
Or, if all of the elements are fully ordered, so that == is
also defined on them, and we can assume that it corresponds to
the equivalence relationship established by the weak partial
ordering:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
int i = 0;
while ( i != N && !(lhs[i] == rhs[i]) ) {
++ i;
}
return i != N && lhs[i] < rhs[i];
}
};
All that remains is to somehow translate this into something
that can process an arbitrary ordering of elements of arbitrary
types. There's an old saying that the solution to every problem
is an additional level of indirection, and it applies here.
First, we need some means of handling the different types of
each element. Polymorphism seems appropriate (although
templates could be made to work if the order in which the
elements were evaluated were fixed at compile time):
struct CompareOneElementOfC
{
virtual bool isLessThan( C const& lhs, C const& rhs) const = 0;
virtual bool isEqual( C const& lhs, C const& rhs) const = 0;
};
template <typename T, T C::*ptr>
struct ConcreteCompareOneElementOfC : public CompareOneElementOfC
{
virtual bool isLessThan( C const& lhs, C const& rhs) const
{
return lhs.*ptr < rhs.*ptr;
}
virtual bool isEqual( C const& lhs, C const& rhs) const
{
return lhs.*ptr == rhs.*ptr;
}
};
Depending on the types of the elements, you may need to hand
write specific concrete instances. And if any of the elements
doesn't support total ordering, you will have to omit the
isEqual, and modify the following code accordingly.
Having got this far, we need exactly one static instance of each
concrete Compare:
ConcreteCompareOneElementOfC<int, &C::a> const c1;
ConcreteCompareOneElementOfC<double, &C::b> const c2;
// ...
Finally, put the addresses of these instances in a table:
CompareOneElementOfC const* const cmp[] = { &c1, &c2 ... };
You can have different tables for different orderings. If there
are only a few, define static tables for each, and be done with
it. If the orderings can be arbitrary, create the table on the
fly before each sort, in the desired order.
Finally:
class Compare
{
CompareOneElementOfC const* const* begin;
CompareOneElementOfC const* const* end;
public:
template< size_t N >
Compare( CompareOneElementOfC const* const (&cmp)[N] )
: begin( cmp )
, end( cmp + N )
{
}
bool
operator()( C const& lhs, C const& rhs ) const
{
auto current = begin;
while ( current != end && (*current)->isEqual( lhs, rhs ) ) {
++ current;
}
return current != end && (*current)->isLessThan( lhs, rhs );
}
}
(Please note that I haven't actually tested this code, so there
are probably typos and other errors. Still, the basic idea
should be there.)
I think just overloading operator < will work for you.
struct Struct {
int member1;
int member2;
bool operator<(const Struct& rhs) const {
if (member1 != rhs.member1)
return member1 < rhs.member1
else
return member2 > rhs.member2
}
};
This way whenever any 2 instances of Struct are compared, they will be compared by the comparison function defined in operator <.
So a simple std::sort(vec.begin(), vec.end()) will just work!
EDIT:
Otherwise you can always define a functor which can be used to compare each element. This is just a class with an overloaded operator () which is used for comparison.
class ComparisonClass {
public:
bool operator()(const Struct& lhs, const Struct& rhs) {
if (lhs.member1 != rhs.member1)
return lhs.member1 < rhs.member1
else
return lhs.member2 > rhs.member2
}
};
You can additionally define some member values of the ComparisonClass which define the order of comparisons.
Using it would be calling it like so std::sort(vec.begin(), vec.end(), ComparisonClass());
EDIT2:
Slightly more elaborate code -
class ComparisonClass {
public:
bool operator()(const Struct& lhs, const Struct& rhs) {
for(int i=0; i<m_comparisonOrder.size(); i++) {
int pos = m_comparisonOrder[i];
if (lhs[pos] != rhs[pos]) {
if (m_comparisonType[pos])
return lhs[pos] < rhs[pos];
else
return lhs[pos] > rhs[pos];
}
}
}
std::vector<int> m_comparisonOrder.
std::vector<bool> m_comparisonType;
};
Here I'm assuming that Struct has an operator [] which returns the appropriate member variable.
Why not have a specialized comparator function which first checks member1 and if equal then checks member2?
Like
bool comparator(const MyStruct& s1, const MyStruct& s2)
{
if (s1.member1 == s2.member1)
return s1.member2 > s2.member2;
else
return s1.member1 < s2.member1;
}
In C++03, I'd like to create a std::set where when iterating, one integer comes first, after that, I don't care what order, but I need an ordering to ensure there are no duplicates in the set. For example, if I had a set of years, and when iterating I want 2010 to be processed before all other years.
std::set<int> years;
// I do not know the set of years up front, so cannot just make a vector, plus
// there could potentially be duplicates of the same year inserted more than
// once, but it should only appear once in the resultant set.
years.insert(2000);
years.insert(2001);
years.insert(2010);
years.insert(2011);
years.insert(2013);
for (std::set<int>::iterator itr = years.begin(); itr != years.end(); ++itr) {
process_year(*itr);
}
Basically, I need to provide a comparator for which some year, known at runtime, (e.g. 2010) compares less than all other years, but the remaining years are ordered, but not in any necessary order, just ordered to ensure no duplicates in the set.
struct Comparer
{
int val;
Comparer(int v):val(v) {}
bool operator()(int lhs, int rhs) const {
if (rhs == val) return false;
if (lhs == val) return true;
return lhs < rhs;
}
};
To create an instance of the std::set that orders based on Comparer:
std::set<int, Comparer> instance( Comparer(2010) );
struct my_compare {
my_compare(int y) : allw_less(y) {}
bool operator() (const int& lhs, const int& rhs) const{
if(rhs == allw_less)
return false;
if(lhs == allw_less)
return true;
else
return lhs < rhs;
}
private:
int allw_less;
};
typedef std::set<int, my_compare> setType;
setType years(my_compare(2010));
I have a class with a few numeric fields such as:
class Class1 {
int a;
int b;
int c;
public:
// constructor and so on...
bool operator<(const Class1& other) const;
};
I need to use objects of this class as a key in an std::map. I therefore implement operator<. What is the simplest implementation of operator< to use here?
EDIT:
The meaning of < can be assumed so as to guarantee uniqueness as long as any of the fields are unequal.
EDIT 2:
A simplistic implementation:
bool Class1::operator<(const Class1& other) const {
if(a < other.a) return true;
if(a > other.a) return false;
if(b < other.b) return true;
if(b > other.b) return false;
if(c < other.c) return true;
if(c > other.c) return false;
return false;
}
The whole reason behind this post is just that I found the above implementation too verbose. There ought to be something simpler.
I assume you want to implement lexicographical ordering.
Prior to C++11:
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
bool Class1::operator<(const Class1& other) const
{
return boost::tie(a, b, c) < boost::tie(other.a, other.b, other.c);
}
Since C++11:
#include <tuple>
bool Class1::operator<(const Class1& other) const
{
return std::tie(a, b, c) < std::tie(other.a, other.b, other.c);
}
I think there is a misunderstanding on what map requires.
map does not require your class to have operator< defined. It requires a suitable comparison predicate to be passed, which conveniently defaults to std::less<Key> which uses operator< on the Key.
You should not implement operator< to fit your key in the map. You should implement it only if you to define it for this class: ie if it's meaningful.
You could perfectly define a predicate:
struct Compare: std::binary_function<Key,Key,bool>
{
bool operator()(const Key& lhs, const Key& rhs) const { ... }
};
And then:
typedef std::map<Key,Value,Compare> my_map_t;
It depends on if the ordering is important to you in any way. If not, you could just do this:
bool operator<(const Class1& other) const
{
if(a == other.a)
{
if(b == other.b)
{
return c < other.c;
}
else
{
return b < other.b;
}
}
else
{
return a < other.a;
}
}
A version which avoids multiple indentation is
bool operator<(const Class1& other) const
{
if(a != other.a)
{
return a < other.a;
}
if(b != other.b)
{
return b < other.b;
}
return c < other.c;
}
The "Edit 2" version of the author has on average more comparisons than this solution. (worst case 6 to worst case 3)
You could do:
return memcmp (this, &other, sizeof *this) < 0;
but that has quite a lot of of caveats - no vtbl for example and plenty more I'm sure.