compare function for upper_bound / lower_bound - c++

I want to find the first item in a sorted vector that has a field less than some value x.
I need to supply a compare function that compares 'x' with the internal value in MyClass but I can't work out the function declaration.
Can't I simply overload '<' but how do I do this when the args are '&MyClass' and 'float' ?
float x;
std::vector< MyClass >::iterator last = std::upper_bound(myClass.begin(),myClass.end(),x);

What function did you pass to the sort algorithm? You should be able to use the same one for upper_bound and lower_bound.
The easiest way to make the comparison work is to create a dummy object with the key field set to your search value. Then the comparison will always be between like objects.
Edit: If for some reason you can't obtain a dummy object with the proper comparison value, then you can create a comparison functor. The functor can provide three overloads for operator() :
struct MyClassLessThan
{
bool operator() (const MyClass & left, const MyClass & right)
{
return left.key < right.key;
}
bool operator() (const MyClass & left, float right)
{
return left.key < right;
}
bool operator() (float left, const MyClass & right)
{
return left < right.key;
}
};
As you can see, that's the long way to go about it.

You can further improve Mark's solution by creating a static instance of MyClassLessThan in MyClass
class CMyClass
{
static struct _CompareFloatField
{
bool operator() (const MyClass & left, float right) //...
// ...
} CompareFloatField;
};
This way you can call lower_bound in the following way:
std::lower_bound(coll.begin(), coll.end(), target, CMyClass::CompareFloatField);
This makes it a bit more readable

Pass a lambda function to upper_bound
float x;
MyClass target;
target.x_ = x;
std::vector< MyClass >::iterator last =
std::upper_bound(myClass.begin(),myClass.end(),target,
[](const MyClass& a, const MyClass& b){return a.x_ < b.x_;});

I think what you need is std::bind2nd(std::less<MyClass>(), x). But, of course, the operator< must be defined for MyClass.
Edit: oh and I think you will need a constructor for MyClass that accepts only a float so that it can be implicitly converted. However, there might be a better way to do this.

Related

Sorting a list by a struct member in c++

I have a list filled with this struct:
struct singlePaymentStruct
{
std::string payer;
int payment;
double amount;
std::time_t timeRec;
singlePaymentStruct() {
payer="Empty";
payment=0;
amount=0;
timeRec = time(0);
}
};
I want to be able to sort this list by any of the fields. How exactly do I do this?
I didn't quite understand how sort method works with something more complex than just a list of records...
Solution found:
singlePaymentList.sort( []( const singlePaymentStruct &a, const singlePaymentStruct &b)
{return a.payer > b.payer;}
);
1.overloading operator<
you can do this by overloading the < operator
struct Foo{
int bar;
bool operator<(Foo &x){
return bar < x.bar;
}
};
2.using lambda expressions
(what is lambda expression?)
Foo array[10];
std::sort(array,array + 10,[](Foo const &l, Foo const &r) {
return l.bar < r.bar; });
3.using custom compare functions
If the possible fields to be used for sorting are known prior, it may be easier to read to implement custom compare functions specifically for the sorting.
struct Foo {
int bar;
SpecialType daa; // Assume daa.IsLessThan() available.
static bool lessBar(const Foo& l, const Foo& r) {
return l.bar < r.bar;
}
static bool lessDaa(const Foo& l, const Foo& r) {
return l.daa.IsLessThan(r.daa);
}
};
Foo array1[10]; // To be sorted by Foo::bar
Foo array2[10]; // To be sorted by Foo::daa
std::sort(array1, array1+10, Foo::lessBar);
std::sort(array2, array2+10, Foo::lessDaa);
std::sort accepts a third optional parameter that is a comparator function. This function should behave as < between elements (i.e. return true when the first is "less than" the second.
For example to sort an std::vector of your structures on increasing payment value what you can do is:
std::sort(data.begin(), data.end(),
[](const singlePaymentStruct& a, const singlePaymentStruct& b) {
return a.payment < b.payment;
});
let the array be struct singlePaymentStruct a[N]
sort(a,a+N,cmp);
bool cmp(struct singlePaymentStruct x, struct singlePaymentStruct y)
{
return x.field < y.field ; //or anything you want to do and return boolean
}
How it works under the hood?
Simply put basically it uses some sorting algoritm like quicksort or mergesort.
Why do we specify comparator functor ?
Well we need that comparator functor to decide the ordering of elements.
The basic thing is in any sorting algortihm the basic operation is comparison..and if we can specify that we are basically controlling the sorting operation.
Hope now you get the pieces together. That's why cmp() takes two values which it will compare and based on which order them.

std::unordered_set of pointers

I have the following struct
struct MyClass {
int myInt;
std::map<int, int> myMap;
};
I want to use unordered_set<MyClass*, PointedObjHash, PointedObEq> but I can't find a valid way to declare PointedObEq.
I tried
struct PointedObjHash {
size_t operator() (MyClass* const& c) const {
std::size_t seed = 0;
boost::hash_combine(seed, c->myInt);
boost::hash_combine(seed, c->myMap);
return seed;
}
and I hope it is fine, but I can't find a way to declare PointedObjEq
--- EDIT ---
If declare operator== inside the class debug never breaks, but I think 'cause MyClass == MyClass* never happens...
struct MyClass {
...
...
bool operator==(MyClass* const& c) {
return this->myInt == c->myInt & this->myMap == c->myMap;
}
If declare operator== inside the class debug never breaks, but I think 'cause MyClass == MyClass* never happens...
The unordered_set needs to use operator== (or PointedObjEq) to double-check the results of the hash function. The hash provides approximate equality, the equality function is used to weed out false positives.
If you've tested adding the same value to the set twice, then you've tested the equality function. To be sure, of course, you can have it print something to the console.
Since it's impossible to define an operator== function with two pointer operands, the PointedObjEq class will be necessary. Note that it takes a MyClass const * on both sides. Also, there's no need to use a reference to a pointer.
So,
struct PointedObjEq {
bool operator () ( MyClass const * lhs, MyClass const * rhs ) const {
return lhs->myInt == rhs->myInt
&& lhs->myMap == rhs->myMap;
}
};
This should do:
struct PointedObEq {
bool operator()(MyClass const * lhs, MyClass const * rhs) const {
return lhs->myInt == rhs->myInt && lhs->myMap == rhs->myMap;
}
};
The reason why your solution does not work is because you have effectively written a mechanism to compare a MyClass with a MyClass*, when you actually need something to compare a MyClass* with a MyClass*.
P.S.: My original answer passed the pointers by const&. Thinking about it, that's a strange coding style, so I changed it to pass the pointers by value.
typedef MyClass* PtrMyClass;
struct PointedObjCompare
{ // functor for operator==
bool operator()(const PtrMyClass& lhs, const PtrMyClass& rhs) const
{
// your code goes here
}
};
std::unordered_set < MyClass*, PointedObjHash, PointedObjCompare > myset;

C++ list::sort of classes by members

How can I sort a list of classes by a certain member variable?
class Klasse {
int _a;
int _b;
}
...
list<Klasse> liste;
liste.sort(); // sorts by _a
liste.sort(?); // how to sort by _b now?
You would use a comparator object. Here's an example using a lambda.
std::list<Klasse> liste;
liste.sort([](Klasse const & lhs, Klasse const & rhs) {
return lhs._b < rhs._b;
});
See the reference.
You can write a comparison function - basically anything that can be called with two arguments of the element type of your list, and this call returns value convertible to bool. Such "anything" can be a lambda, function object, or simply just a function:
bool klasse_sort_by_b(const Klasse& l, const Klasse& r)
{
return l._b < r._b;
}
liste.sort(klasse_sort_by_b);
you need this implementation of sort:
template<typename Compare>
void sort (Compare comp);
then pass inside a compare function like:
bool compareByA( const Klasse& first, const Klasse& second ){
return first._a < second._a;
}
then call it:
std::list<Klasse> lst;
...
lst.sort(compareByA);
lst.sort(compareByB);
http://www.cplusplus.com/reference/list/list/sort/
You should write your own comparer, example and usage in the link ;)
here is the code example as promised
(thanks for the constructive criticism)
bool compare_by_b (const Klasse& first, const Klasse& second)
{
return first._b < second._b ;
}
liste.sort(compare_by_b);
Yes, and all you have to do is implement a comparator class, or overload the comparison Klasse::operator< operators. For reference on the sort method, see this.

c++ priority_queue initialization. Why can we ignore const Compare&

class Star {
public:
// The distance between this star to the Earth.
double distance() const { return sqrt(x_ * x_ + y_ * y_ + z_ * z_); }
bool operator<(const Star& s) const { return distance() < s.distance(); }
int ID_;
double x_, y_, z_;
};
priority_queue<Star, vector<Star>> max_heap;
Look at last line. This is priority_queue max_heap's initialization. Why it ignore the c++ const Compare&.
I thought it would be
priority_queue<Star, vector<Star>, Star> max_heap;
It looks different as below one, which I understand.
class mycomparison
{
bool reverse;
public:
mycomparison(const bool& revparam=false)
{reverse=revparam;}
bool operator() (const int& lhs, const int&rhs) const
{
if (reverse) return (lhs>rhs);
else return (lhs<rhs);
}
};
int main ()
{
int myints[]= {10,60,50,20};
std::priority_queue<int> first;
std::priority_queue<int> second (myints,myints+4);
std::priority_queue<int, std::vector<int>, std::greater<int> >
third (myints,myints+4);
// using mycomparison:
typedef std::priority_queue<int,std::vector<int>,mycomparison> mypq_type;
mypq_type fourth; // less-than comparison
mypq_type fifth (mycomparison(true)); // greater-than comparison
return 0;
}
I read this page:
http://www.cplusplus.com/reference/queue/priority_queue/priority_queue/
cannot get the definitive definition of priority_queue constructor paradigm.
Also, Why sometimes it overloads "<" as comparator. Sometimes overloads "()" as comparator?
thanks
The default comparison is std::less< Star > which will call the operator < you have defined.
Template type parameters can have deault arguments, just like function parameters. It's the same with the default container type, which is std::vector< Star >. Actually you can write the declaration simply as
priority_queue<Star> max_heap;
Also, Why sometimes it overloads "<" as comparator. Sometimes overloads "()" as comparator?
The comparator is always a Callable object, that is, a function or function-like object (functor). The things to be compared are passed using function-call notation with parentheses. std::less is the adaptor which makes a given bool operator< (T, T) overload accessible as the member operator() of a functor.
For example, here is how std::less may be implemented:
template< typename T >
struct less {
bool operator () ( T const & lhs, T const & rhs ) const
{ return lhs < rhs; } // Calls Star::operator < ()
};
std::less is actually an object type, and such an object is actually stored inside the priority_queue. Its operator() is what makes the comparison. The call to your operator < happens this way.

How to create a set with my customized comparison in c++

Could someone explain me what is going on in this example here?
They declare the following:
bool fncomp (int lhs, int rhs) {return lhs<rhs;}
And then use as:
bool(*fn_pt)(int,int) = fncomp;
std::set<int,bool(*)(int,int)> sixth (fn_pt)
While the example for the sort method in algorithm library here
can do like this:
bool myfunction (int i,int j) { return (i<j); }
std::sort (myvector.begin()+4, myvector.end(), myfunction);
I also didn't understand the following:
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
I was trying to make a set of C-style string as follows:
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
set <wrap, compare> myset;
I thought I could create a set defining my sorting function in a similar as when I call sort from algorithm library... once it didn't compile I went to the documentation and saw this syntax that got me confused... Do I need to declare a pointer to a function as in the first example i pasted here?
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
Defines a functor by overloading the function call operator. To use a function you can do:
int main() {
std::set <wrap, bool (*)(wrap,wrap)> myset(compare);
return 0;
}
Another alternative is to define the operator as a part of the wrap class:
struct wrap {
char grid[7];
bool operator<(const wrap& rhs) const {
return strcmp(this->grid, rhs.grid) == -1;
}
};
int main() {
wrap a;
std::set <wrap> myset;
myset.insert(a);
return 0;
}
You're almost there... here's a "fixed" version of your code (see it run here at ideone.com):
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2) // more efficient: ...(const wrap& e1, const wrap# w2)
{
return strcmp(w1.grid, w2.grid) < 0;
}
set <wrap, bool(*)(wrap, wrap)> myset(compare);
int main() {
wrap w1 { "abcdef" };
wrap w2 { "ABCDEF" };
myset.insert(w1);
myset.insert(w2);
std::cout << myset.begin()->grid[0] << '\n';
}
"explain [to] me what is going on in this example"
Well, the crucial line is...
std::set<wrap, bool(*)(wrap, wrap)> myset(compare);
...which uses the second template parameter to specify the type of function that will perform comparisons, then uses the constructor argument to specify the function. The set object will store a pointer to the function, and invoke it when it needs to compare elements.
"the example for the sort method in algorithm library..."
std::sort in algorithm is great for e.g. vectors, which aren't automatically sorted as elements are inserted but can be sorted at any time. std::set though needs to maintain sorted order constantly, as the logic for inserting new elements, finding and erasing existing ones etc. all assumes the existing elements are always sorted. Consequently, you can't apply std::sort() to an existing std::set.
"this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
operator()(...) can be invoked on the object using the same notation used to call a function, e.g.:
classcomp my_classcomp;
if (my_classcomp(my_int1, my_int_2))
std::cout << "<\n";
As you can see, my_classcomp is "called" as if it were a function. The const modifier means that the code above works even if my_classcomp is defined as a const classcomp, because the comparison function does not need to modify any member variables of the classcomp object (if there were any data members).
You almost answered your question:
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
struct wrap_comparer
{
bool operator()(const wrap& _Left, const wrap& _Right) const
{
return strcmp(_Left.grid, _Right.grid) == -1;
}
};
// declares pointer to function
bool(*fn_pt)(wrap,wrap) = compare;
// uses constructor with function pointer argument
std::set<wrap,bool(*)(wrap,wrap)> new_set(fn_pt);
// uses the function directly
std::set<wrap,bool(*)(wrap,wrap)> new_set2(compare);
// uses comparer
std::set<wrap, wrap_comparer> new_set3;
std::sort can use either a function pointer or a function object (http://www.cplusplus.com/reference/algorithm/sort/), as well as std::set constructor.
const modifier after function signature means that function can't modify object state and so can be called on a const object.