A collection of utilities for comparators.
More...
A collection of utilities for comparators.
This file contains some lightweight class templates which simplify the (re-)usage and composition of comparator classes:
- ReverseComparator (reverse the direction of comparison)
- LexicographicComparator (combine comparators lexicographically)
- PointerComparator (compare pointers like the type they point to)
We provide corresponding "make-functions" so that you will not need to write out the type names in the template instantiation.
We explain this with a simple example. First a few prerequisites.
The class IntRealString has three data members. The class IntRealStringVector is a vector of IntRealString. We add some print() methods for convenience.
class IntRealString
{
public:
IntRealString(
Int i,
float r, String s) :
i_(i), r_(r), s_(s) {}
IntRealString(const IntRealString & rhs) :
i_(rhs.i_), r_(rhs.r_), s_(rhs.s_) {}
void print() const
{
std::cout << "(" << i_ << ", " << r_ << ", " << s_ << ")" << std::endl;
}
float r_;
String s_;
};
class IntRealStringVector :
public std::vector<IntRealString>
{
public:
void print() const
{
for (
Size i = 0; i < size(); ++i) (*
this)[i].print();
std::cout << std::endl;
}
};
Now we will exercise various ways of sorting such a vector.
Of course, we could use the std::sort algorithm with a comparison function like the following.
bool lessByInt(IntRealString left, IntRealString right)
{
return left.i_ < right.i_;
}
This is straightforward but does not generalize well. Instead we introduce three comparator classes:
struct LessByInt :
std::binary_function<IntRealString, IntRealString, bool>
{
bool operator()(IntRealString left, IntRealString right) const { return left.i_ < right.i_; }
};
struct LessByReal :
std::binary_function<IntRealString, IntRealString, bool>
{
bool operator()(IntRealString left, IntRealString right) const { return left.r_ < right.r_; }
};
struct LessByString :
std::binary_function<IntRealString, IntRealString, bool>
{
bool operator()(IntRealString left, IntRealString right) const { return left.s_ < right.s_; }
};
Note how the std::binary_function template provides the necessary type information (sometimes this is called "reflection").
Now we show various uses of the reverseComparator and lexicographicComparator function templates.
{
IntRealStringVector vec;
vec.push_back(IntRealString(1, 4.5f, "paul"));
vec.push_back(IntRealString(2, 4.5f, "josie"));
vec.push_back(IntRealString(1, 4.5f, "john"));
vec.push_back(IntRealString(2, 3.9f, "kim"));
std::cout << "After initialization:" << std::endl;
vec.print();
std::cout << "Sorted using lessByInt function:" << std::endl;
std::sort(vec.begin(), vec.end(), lessByInt);
vec.print();
std::cout << "Sorted using LessByInt comparator class:" << std::endl;
std::sort(vec.begin(), vec.end(), LessByInt());
vec.print();
std::cout << "Sorted using reversed LessByInt comparator class:" << std::endl;
vec.print();
std::cout << "Sorted using lexicographic order: 1. LessByInt, 2. LessByReal" << std::endl;
vec.print();
std::cout << "Sorted using lexicographic order: 1. reversed LessByInt, 2. LessByReal, 3. LessByString" << std::endl;
std::sort(vec.begin(), vec.end(),
(
LessByReal()
),
LessByString()
)
);
vec.print();
And here is an application of the pointerComparator function template:
std::vector<const IntRealString *> ptr_vec;
for (
Size i = 0; i < vec.size(); ++i)
{
ptr_vec.push_back(&vec[i]);
}
std::cout << "ptr_vec before sorting" << std::endl;
for (
Size i = 0; i < ptr_vec.size(); ++i)
ptr_vec[i]->print();
std::cout << std::endl;
std::cout << "ptr_vec after sorting with pointerComparator(LessByString())" << std::endl;
for (
Size i = 0; i < ptr_vec.size(); ++i)
ptr_vec[i]->print();
std::cout << std::endl;
return 0;
}
The output of the example program is:
After initialization:
(1, 4.5, paul)
(2, 4.5, josie)
(1, 4.5, john)
(2, 3.9, kim)
Sorted using lessByInt function:
(1, 4.5, paul)
(1, 4.5, john)
(2, 4.5, josie)
(2, 3.9, kim)
Sorted using LessByInt comparator class:
(1, 4.5, paul)
(1, 4.5, john)
(2, 4.5, josie)
(2, 3.9, kim)
Sorted using reversed LessByInt comparator class:
(2, 4.5, josie)
(2, 3.9, kim)
(1, 4.5, paul)
(1, 4.5, john)
Sorted using lexicographic order: 1. LessByInt, 2. LessByReal
(1, 4.5, paul)
(1, 4.5, john)
(2, 3.9, kim)
(2, 4.5, josie)
Sorted using lexicographic order: 1. reversed LessByInt, 2. LessByReal, 3. LessByString
(2, 3.9, kim)
(2, 4.5, josie)
(1, 4.5, john)
(1, 4.5, paul)
ptr_vec before sorting
(2, 3.9, kim)
(2, 4.5, josie)
(1, 4.5, john)
(1, 4.5, paul)
(1, 4.5, john)
(2, 4.5, josie)
(2, 3.9, kim)
(1, 4.5, paul)
Note that pointerComparator can also be used with full-blown iterator classes. (It should work with everything that provides an operator*(), but the typedefs will always be pointers.)
Note that these templates can also be used with different types for "left" and "right".