How to pass a custom comparator to sort?
Define your own <=>
, and include Comparable. This is from the Comparable doc:
class SizeMatters
include Comparable
attr :str
def <=>(an_other)
str.size <=> an_other.str.size
end
def initialize(str)
@str = str
end
def inspect
@str
end
end
s1 = SizeMatters.new("Z")
s2 = SizeMatters.new("YY")
s3 = SizeMatters.new("XXX")
s4 = SizeMatters.new("WWWW")
s5 = SizeMatters.new("VVVVV")
s1 < s2 #=> true
s4.between?(s1, s3) #=> false
s4.between?(s3, s5) #=> true
[ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV]
You don't actually have to include Comparable, but you get extra functionality for free if you do that after having defined <=>
.
Otherwise, you can use Enumerable's sort
with a block if your objects implement <=>
already.
Another way to use several different comparisons is to use lambdas. This uses the new 1.9.2 declaration syntax:
ascending_sort = ->(a,b) { a <=> b }
descending_sort = ->(a,b) { b <=> a }
[1, 3, 2, 4].sort( & ascending_sort ) # => [1, 2, 3, 4]
[1, 3, 2, 4].sort( & descending_sort ) # => [4, 3, 2, 1]
foo = ascending_sort
[1, 3, 2, 4].sort( & foo ) # => [1, 2, 3, 4]
Custom Comparator - Java
Comparison-based sorts distinguish values by determining whether or not they are <
, =
, or >
.
For example, 3 < 4
, 4 = 4
, 4 > 3
.
Java Comparators use the convention that
cmp(a, b) < 0
meansa < b
cmp(a, b) = 0
meansa = b
cmp(a, b) > 0
meansa > b
Note that this means if cmp(x, y) = x - y
, then you get the normal ordering for the integers. You can check yourself that cmp(x, y) = -(x- y) = y - x
gives you the reverse ordering.
When sorting (or doing something else that moves generic elements around by their order, like a PriorityQueue), the algorithm will (repeatedly) consult the comparator to determine whether or not values it has been given are <
, =
, or >
.
std::sort with custom comparator
std::sort
accepts a functor
. This is any object that can be called (with the correct parameters). The function achieves this by using templates, like the following
template<typename Iter, typename Comp>
void sort(Iter begin, Iter end, Comp compare) { ... }
IntComparator1
, 2, and 3 are all valid functors for this comparator, since they can all be called using operator() with 2 integers.
Also like you said, the third option is indeed usually more intuitive.
How to add a comparator to a custom sort function
Considering you have a class or struct CustomType
Pre c++11
struct CustomCompare
{
bool operator ()(const CustomType& a, const CustomType& b)
{
return a.Watever < b.Watever;
}
};
//usage
merge(vector<CustomType> ..., CustomCompare());
Post c++11, using lambdas:
auto CustomCompare = [](const CustomType & a,const CustomType& b)
{
return a. .... ;
};
//usage
merge(vector<CustomType> ..., CustomCompare);
There is third option:
You can use std::less
but there must exist an operator <
that takes your CustomType
as arguments
Example:
struct CustomType
{
//...
bool operator < (const CustomType& other)const
{
return this->Whatever < other.Whatever;
}
};
And you can specialize std::less
:
namespace std
{
template <>
struct less <CustomType>
{
bool operator()(const CustomType & a, const CustomType & b)
{
return ...
}
};
}
Related Topics
Inverse of 'Module#Singleton_Class'
How to Use Ruby Regexp to Substitute String with a "Callback Function"-Like Manipulation
Ruby Float#Round Method Behaves Incorrectly with Round(2)
How to Save Unescaped & in Nokogiri Xml
Is Every Relavant Calculation Performed Every Time the Page Is Loaded
Replacing Text in One CSV Column Using Fastercsv
How to Export Environment Variable Permanently Using Ruby
How to Ruby on Rails Authentication with Ldap
How to Use Ruby for Shell Scripting
Rmagick Installation: Can't Find Magickwand.H
Checking If a Variable Is Not Nil and Not Zero in Ruby
Recommended Approach to Monkey Patching a Class in Ruby
Does Objective-C Support Mixin Like Ruby
Mountain Lion - Libxml & Nokogiri