binary_search, find_if and <functional> - c++

std::find_if takes a predicate in one of it's overloaded function. Binders make it possible to write EqualityComparators for user-defined types and use them either for dynamic comparison or static comparison.
In contrast the binary search functions of the standard library take a comparator and a const T& to the value that should be used for comparison. This feels inconsistent to me and could possibly more inefficient as the comparator has to be called with both arguments every time instead of having the constant argument bound to it. While it could be possible to implement std::binary_search in a way to use std::bind this would require all comparators to inherit from std::binary_function. Most code I've seen doesn't do that.
Is there a possible benefit from letting comparators inherit from std::binary_function when using it with algorithms that take a const T& as a value instead of letting me use the binders? Is there a reason for not providing predicate overloads in those functions?

A single-argument predicate version of std::binary_search wouldn't be able to complete in O(log n) time.
Consider the old game "guess the letter I'm thinking of". You could ask: "Is it A?" "Is it B?".. and so on until you reached the letter. That's a linear, or O(n), algorithm. But smarter would be to ask "Is it before M?" "Is it before G?" "Is it before I?" and so on until you get to the letter in question. That's a logarithmic, or O(log n), algorithm.
This is what std::binary_search does, and to do this in needs to be able to distinguish three conditions:
Candidate C is the searched-for item X
Candidate C is greater than X
Candidate C is less than X
A one-argument predicate P(x) says only "x has property P" or "x doesn't have property P". You can't get three results from this boolean function.
A comparator (say, <) lets you get three results by calculating C < X and also X < C. Then you have three possibilities:
!(C < X) && !(X < C) C is equal to X
C < X && !(X < C) C is less than X
!(C < X) && X < C C is greater than X
Note that both X and C get bound to both parameters of < at different times, which is why you can't just bind X to one argument of < and use that.
Edit: thanks to jpalecek for reminding me binary_search uses <, not <=.
Edit edit: thanks to Rob Kennedy for clarification.

They are completely different algorithms: find_if looks linearly for the first item for which the predicate is true, binary_search takes advantage that the range is sorted to test in logarithmic time if a given value is in it.
The predicate for binary_search specifies the function according to which the range is ordered (you'd most likely want to use the same predicate you used for sorting it).
You can't take advantage of the sortedness to search for a value satisfying some completely unrelated predicate (you'd have to use find_if anyway). Note however, that with a sorted range you can do more than just test for existence with lower_bound, upper_bound and equal_range.
The question, what is the purpose of std::binary_function is an interesting one.
All it does is provide typedefs for result_type, first_argument_type and second_argument_type. These would allow the users, given a functor as a template argument, to find out and use these types, e.g
template <class T, class BinaryFunction>
void foo(const T& a, const T& b, BinaryFunction f)
{
//declare a variable to store the result of the function call
typename BinaryFunction::result_type result = f(a, b);
//...
}
However, I think the only place where they are used in the standard library is creating other functor wrappers like bind1st, bind2nd, not1, not2. (If they were used for other purposes, people would yell at you any time you used a function as a functor since it would be an unportable thing to do.)
For example, binary_negate might be implemented as (GCC):
template<typename _Predicate>
class binary_negate
: public binary_function<typename _Predicate::first_argument_type,
typename _Predicate::second_argument_type, bool>
{
protected:
_Predicate _M_pred;
public:
explicit
binary_negate(const _Predicate& __x) : _M_pred(__x) { }
bool
operator()(const typename _Predicate::first_argument_type& __x,
const typename _Predicate::second_argument_type& __y) const
{ return !_M_pred(__x, __y); }
};
Of course, operator() could perhaps just be a template, in which case those typedefs would be unnecessary (any downsides?). There are probably also metaprogramming techniques to find out what the argument types are without requiring the user to typedef them explicitly. I suppose it would somewhat get into the way with the power that C++0x gives - e.g when I'd like to implement a negator for a function of any arity with variadic templates...
(IMO the C++98 functors are a bit too inflexible and primitive compared for example to std::tr1::bind and std::tr1::mem_fn, but probably at the time compiler support for metaprogramming techniques required to make those work was not that good, and perhaps the techniques were still being discovered.)

This is a misunderstanding of the Functor concept in C++.
It has nothing to do with inheritance. The property that makes an object a functor (eligible for passing to any of the algorithms) is validity of the expression object(x) or object(x, y), respectively, regardless whether it is a function pointer or an object with overloaded function call operator. Definitely not inheritance from anything. The same applies for std::bind.
The use of binary functors as comparators comes from the fact that comparators (eg. std::less) are binary functors and it's good to be able to use them directly.
IMHO there would be no gain in providing or using the predicate version you propose (after all, it takes just passing one reference). There would be no (performance) gain in using binders, because it does the same thing as the algorithm (bind would pass the extra argument in lieu of the algorithm).

Related

Searching std::map in O(n) for a partial key

I have a (C++ 14) map
using MyTuple = tuple<A, B, C>;
map<MyTuple, MyData>
where MyTuple has the obvious operator<() that compares first A, then B, then C.
I want to do an O(ln N) search for keys that match some constant (a, b). Obviously if any are present they will be consecutive. So basically I want
map<MyTuple, MyData> my_map = GetMyData();
tuple<A, B> my_key = make_tuple(a, b);
auto iter = my_map.lower_bound_if([my_key](const MyTuple& key) {
if (get<0>(my_key) == get<0>(key) &&
get<1>(my_key) == get<1>(key)) {
return true;
}
return false;
});
while( /* iter.first is still an (a,b) */) {
// Do something with iter.
// Increment iter.
}
But there's no function map::lower_bound_if and yet map::find and map::lower_bound take a full MyTuple. I could (hackishly) find a value of C that is lower than anything in my data, though this is fragile over time. I could write the function myself though it would likely be dependent on my current local implementation of std::map.
Have I missed an obvious solution?
Update
The solution, which I've accepted, was to use partial key mathing in the compare function (transparent operator functors), which are new since C++14 and took me longer than I care to admit to understand. This article was a good mental ice breaker and this SO question was good once I understood.
The basic insight is to consider a set of objects sorted on some key that is part of the object. For example, a set of employees with the sort key being employee.id. And we'd like to be able to search on employee or on the integer id. So we make a struct of bool operator()() that encompasses the various ways we might want to compare. And then overload resolution does the rest.
In my case, this meant that I could provide the strict total ordering I needed to make my code work but also provide a comparator that only imposes a partial ordering which I only use for lower_bound() lookups. Because the extra comparator doesn't provide a strict total ordering, it would not be suitable for, say, find() unless we meant "find one of".
As an aside, I realised after posing my question that it was a bit daft in a way. I wanted an O(ln n) lookup but wanted to use a different sort function. That can't be guaranteed to work: it depends on me providing a sort function that really does provide an ordering that is a sub-ordering of the strict total ordering. If I did otherwise, it would clearly fail. And so this is why there's no O(ln n) function find_if(), because that can only be linear.
Indeed, the technique of transparent operator functors is clever but does depend on the programmer providing no worse than a subordering.
In c++14 you can use the overload to search on a partial key:
struct CompareFirstTwo {
using is_transparent = void;
bool operator()(const tuple<A, B, C>& lhs, const tuple<A, B, C>& rhs) const ...
bool operator()(const tuple<A, B>& lhs, const tuple<A, B, C>& rhs) const ...
bool operator()(const tuple<A, B, C>& lhs, const tuple<A, B>& rhs) const ...
};
Use the comparator above in a call to equal_range to ignore the third field in the tuple.
One approach is to put "any value you like" for C, use lower_bound, and be aware that the values you are looking for might be before the lower_bound, as well as after, so you might need to do some operator-- to find the first one, just as you would use operator++ to find the last one? The number of operations in order to find the range in advance does not change, but there is an in-advance overhead if you wanted to iterate over them and test for the end of <A,B> on the fly.
Obviously, it would be convenient, but not necessary, if that C was a "hacky" value that compared as the lowest possible C, as that would make the backward search faster, but we have mitigated your risk of fragility?
Another option would be to make your own container that is a map of maps. The outer map would be indexed by <A,B> and the inner map indexed by < C >.
You could then add your own methods to implement a whole-map indexing and iteration using <A,B,C>; and use the existing <A,B> methods to either return the inner map when indexed, or return your iterators as results for lower_bound and upper_bound, that can then be used as a range for all <A,B,allC>.
If you have an order such that x {xa, xb, xc} is always < than y {ya, yb, yc} when f(xa, xb) (and conversely for >), it becomes easy. Consider it as "sort by A and B first".
Then you just need to know your maximal and minimal C value.
Search between lower_bound(a, b, MIN_C) and upper_bound(a, b, MAX_C). Alternatively, as suggested in the comments
A map of tuple<A, B> to map of C to MyData? – Vlad Feinstein
would work.

Different types for `std::sort` comparator in C++

When we provide a comparator function for std::sort, we use the following overload:
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
in which the comparator function for std::sort should have the following syntax:
bool cmp(const Type1 &a, const Type2 &b);
But as you can see a and b may have different types. cppreference says:
The types Type1 and Type2 must be such that an object of type RandomIt
can be dereferenced and then implicitly converted to both of them. ​
But I still cannot understand exactly how we can have 2 different types in a single array when we try to sort it.
Is it possible for someone to provide a small example with different types for std::sort's comparator function?
Its not about what is stored in the array, only one type can ever be stored. It is about what the comparator function is. Take for example this:
struct Animal {};
struct Cat : Animal {};
struct Dog : Animal {};
struct Hound : Dog {};
bool cmp(const Animal &a, const Animal &b);
Even if you have a list of Dogs, Cats or Hounds you can still sort them with the function cmp because they are all implicitly convertible. ie.
std::vector<Hound> hounds;
... // fill hounds
std::sort(hounds.begin(), hounds.end(), cmp);
And you can even imagine cases where Type1 and Type2 are not the same, eg.:
bool cmp(const Animal &a, const Dog &b);
etc ...
Although this would be exceedingly rare.
The types Type1 (Animal) and Type2 (Dog) must be such that an object of type RandomIt (Hound) can be dereferenced and then implicitly converted to both of them. ​Which is true.
The point is that a restriction on the types that a cmp function can take to the same, precludes generality. In some cases this is a good idea, but in this case it would be unreasonably strict and may force problems for edge case implementations. Furthermore, the cmp function used instd::sort is bound by the requirements set out for Compare (probably for simplicity). Compare requirements are used for all sorts of other things, like std::max.
But I still cannot get it exactly how we can have 2 different types in a single array when we try to sort it.
You can't have two different types in an array. The comparator doesn't suggest it's possible. It's specified like that simply because:
The code can be well formed when the types are not the same.
Demanding the same type is a restriction that serves little to no purpose.
So the specification offers a looser contract than is "obvious", in order to help our code be more flexible if needed. As a toy example, say we have this comparator laying around:
auto cmp(int a, long b) -> bool { return a < b; }
Why prevent us from using this perfectly legal (albeit silly) function to sort an array of integers?
But I still cannot get it exactly how we can have 2 different types in a single array when we try to sort it.
You can't.
But the requirements of Compare are not just for sorting arrays, or just for sorting at all!
They're for any time you want to compare one thing to another thing.
Is minutes(42) less than hours(1)? Yes! You may find useful a comparator for such occasions.
Compare is a more general concept that finds uses throughout the language.
Is ti possible that someone provide a small example with different types for std::sort's comparator function
Others have shown examples that indicate how silly you have to get to find a "useful" example to use against std::sort specifically.
But it's not "std::sort's comparator function". It's a comparator function, which you just so happen to be using with std::sort.
It's true that, when doing so, you probably want the particular comparator that you pick to accept operands of the same type.
But I still cannot get it exactly how we can have 2 different types in a single array
You cannot have two different types in a single array.
An array can have objects of only single type. But that single type must be implicitly convertible to both argument types of cmp.
Is ti possible that someone provide a small example with different types for std::sort's comparator function?
Here you go:
int arr[] = {1, 2, 3, 0};
auto cmp = [](const int &a, const long &b) {
return a < b;
};
std::sort(std::begin(arr), std::end(arr), cmp);
Note the two different arguments of cmp. This is just a minimal example, which is technically correct, but admittedly nonsensical. Frankly, I've never encountered a case where it would be useful to have different types for the arguments of a comparison function.
The requirements for a comparator are far looser than you think:
It must accept two dereferenced iterators into the sequence as arguments.
Using an implicit conversion-sequence is fine.
The return-value must be contextually-convertible to bool.
An explicit conversion-operator works just fine.
It must be a copyable and nothrow-destructible complete type.
It must not modify the arguments, so it doesn't interfere with the calling algorithm.
That does not in any way imply the use of constant references if references are used at all.
It must induce a full weak order (cmp(a, b) implies !cmp(b, a), cmp(a, b) && cmp(b, c) implies cmp(a, c)).
So, a valid but fairly useless comparator would be:
template <class... X>
auto useless(X&&...) { return nullptr; }
The type requirements on Compare are not saying much about the elements of the sequence you are sorting, but instead they are allowing all comps for which
if (comp(*first, *other))
is valid.
Most of the time, Type1 will be equal to Type2, but they are not required to be equal.

std::map Requirements for Keys (Design Decision)

When I make a std::map<my_data_type, mapped_value>, what C++ expects from me is that my_data_type has its own operator<.
struct my_data_type
{
my_data_type(int i) : my_i(i) { }
bool operator<(const my_data_type& other) const { return my_i < other.my_i; }
int my_i;
};
The reason is that you can derive operator> and operator== from operator<. b < a implies a > b, so there's operator>. !(a < b) && !(b < a) means that a is neither less than b nor greater than it, so they must be equal.
The question is: Why hasn't the C++ designer require operator== to be explicitly defined? Obviously, operator== is inevitable for std::map::find() and for removing duplicates from the std::map. Why implement 5 operations and call a method twice in order not to compel me to explicitly implement operator==?
operator== is inevitable for std::map::find()
This is where you go badly wrong. map does not use operator== at all, it is not "inevitable". Two keys x and y are considered equivalent for the purposes of the map if !(x < y) && !(y < x).
map doesn't know or care whether you've implemented operator==. Even if you have, it need not be the case that all equivalent keys in the order are equal according to operator==.
The reason for all this is that wherever C++ relies on orders (sorting, maps, sets, binary searches), it bases everything it does on the well-understood mathematical concept of a "strict weak order", which is also defined in the standard. There's no particular need for operator==, and if you look at the code for these standard functions you won't very often see anything like if (!(x < y) && !(y < x)) that does both tests close together.
Additionally, none of this is necessarily based on operator<. The default comparator for map is std::less<KeyType>, and that by default uses operator<. But if you've specialized std::less for KeyType then you needn't define operator<, and if you specify a different comparator for the map then it may or may not have anything to do with operator< or std::less<KeyType>. So where I've said x < y above, really it's cmp(x,y), where cmp is the strict weak order.
This flexibility is another reason why not to drag operator== into it. Suppose KeyType is std::string, and you specify your own comparator that implements some kind of locale-specific, case-insensitive collation rules. If map used operator== some of the time, then that would completely ignore the fact that strings differing only by case should count as the same key (or in some languages: with other differences that are considered not to matter for collation purposes). So the equality comparison would also have to be configurable, but there would only be one "correct" answer that the programmer could provide. This isn't a good situation, you never want your API to offer something that looks like a point of customization but really isn't.
Besides, the concept is that once you've ruled out the section of the tree that's less than the key you're searching for, and the section of the tree for which the key is less than it, what's left either is empty (no match found) or else has a key in it (match found). So, you've already used current < key then key < current, leaving no other option but equivalence. The situation is exactly:
if (search_key < current_element)
go_left();
else if (current_element < search_key)
go_right();
else
declare_equivalent();
and what you're suggesting is:
if (search_key < current_element)
go_left();
else if (current_element < search_key)
go_right();
else if (current_element == search_key)
declare_equivalent();
which is obviously not needed. In fact, it's your suggestion that's less efficient!
Your assumptions aren't correct. Here's what's really happening:
std::map is a class template which takes four template parameters: key type K, mapped type T, comparator Comp and allocator Alloc (the names are immaterial, of course, and only local to this answer). What matters for this discussion is that an object Comp comp; can be called with two key refrences, comp(k1, k2), where k1 and k2 are K const &, and the result is a boolean which imlpements a strict weak ordering.
If you do not specify the third argument, then Comp is the default type std::less<K>, and this (stateless) class imlpements the binary operation as k1 < k2. It does not matter whether this <-operator is a member of K, or a free function, or a template, or whatever.
And that wraps up the story, too. The comparator type is the only datum required to implement an ordered map. Equality is defined as !comp(a, b) && !comp(b,a), and the map only stores one unique key according to this definition of equality.
There is no reason to make additional requirements on the key type, and also there is no logical reason that a user-defined operator== and operator< should at all be compatible. They could both exist, independently, and serve entirely different and unrelated purpose.
A good library imposes the minimal necessary requirements and offers the greatest possible amount of flexibility, and this is precisely what std::map does.
In order to find the element i within the map, we have traversed to element e the tree search will already have tested i < e, which would have returned false.
So either you call i == e or you call e < i, both of which imply the same thing given the prerequisite of finding e in the tree already. Since we already had to have an operator< we don't rely on operator==, since that would increase the demands of the key concept.
You have a faulty assumption:
!(a < b) && !(b < a) means that a is neither less than b nor greater than it, so they must be equal.
It means that they are equivalent, but not necessarily equal. You are free to implement operator< and operator== in such a way that two objects can be equivalent but not equal.
Why hasn't the C++ designer require operator== to be explicitly defined?
To simplify the implementation of types that can be used as keys, and to allow you to use a single custom comparator for types without overloaded operators. The only requirement is that you supply a comparator (either operator< or a custom functor) that defines a partial ordering. Your suggestion would require both the extra work of implementing an equality comparison, and the extra restriction of requiring equivalent objects to compare equal.
The reason why a comparison operator is needed is the way map is implemented: as a binary search tree, which allows you to look up, insert and delete elements in O(log n). In order to build this tree, a strict weak order must be defined for the set of keys. That's why only one operator definition is needed.

C++ STL sort() function, binary predicate

I have a piece of code that confuses me:
sort(data, data+count, greater<int>() );
it is a sort function in the C standard library. I am having trouble figuring out the meaning of the third argument. I have read that it is called a binary predicate. What does that mean and how can I make my own such predicate?
The third argument is called a predicate. You can think of a predicate as a function that takes a number of arguments and returns true or false.
So for example, here is a predicate that tells you whether an integer is odd:
bool isOdd(int n) {
return n & 1;
}
The function above takes one argument, so you could call it a unary predicate. If it took two arguments instead, you would call it a binary predicate. Here is a binary predicate that tells you if its first argument is greater than the second:
bool isFirstGreater(int x, int y) {
return x > y;
}
Predicates are commonly used by very general-use functions to allow the caller of the function to specify how the function should behave by writing their own code (when used in this manner, a predicate is a specialized form of callback). For example, consider the sort function when it has to sort a list of integers. What if we wanted it to sort all odd numbers before all even ones? We don't want to be forced to write a new sort function each time that we want to change the sort order, because the mechanics (the algorithm) of the sort is clearly not related to the specifics (in what order we want it to sort).
So let's give sort a predicate of our own to make it sort in reverse:
// As per the documentation of sort, this needs to return true
// if x "goes before" y. So it ends up sorting in reverse.
bool isLarger(int x, int y) {
return x > y;
}
Now this would sort in reverse order:
sort(data, data+count, isLarger);
The way this works is that sort internally compares pairs of integers to decide which one should go before the other. For such a pair x and y, it does this by calling isLarger(x, y).
So at this point you know what a predicate is, where you might use it, and how to create your own. But what does greater<int> mean?
greater<T> is a binary predicate that tells if its first argument is greater than the second. It is also a templated struct, which means it has many different forms based on the type of its arguments. This type needs to be specified, so greater<int> is the template specialization for type int (read more on C++ templates if you feel the need).
So if greater<T> is a struct, how can it also be a predicate? Didn't we say that predicates are functions?
Well, greater<T> is a function in the sense that it is callable: it defines the operator bool operator()(const T& x, const T& y) const;, which makes writing this legal:
std::greater<int> predicate;
bool isGreater = predicate(1, 2); // isGreater == false
Objects of class type (or structs, which is pretty much the same in C++) which are callable are called function objects or functors.
There is a class template called greater which needs a type argument. So you provide int as one. It became greater<int> and you create an instance of this class and pass it to the function as third argument.
Such an object is called function object or simply functor in C++, as the class overloads () operator. It's a callable entity. Its like this:
template<typename T>
struct greater
{
bool operator()(const T &a, const T &b)
{
//compare a and b and return either true or false.
return a > b;
}
};
If you create an instance of greater<int> and, say, the object is g, then you can write g(100,200) which evaluates to a boolean value, as the expression g(100,200) calls operator(), passing 100 as first argument and 200 as second argument, and operator() compares them and return either true or false.
std::cout << g(100,200) << std::endl;
std::cout << g(200,100) << std::endl;
Output:
0
1
Online demo : http://ideone.com/1HKfC
A binary predicate is any function/object that receives two objects (hence binary) and returns a bool (hence predicate); the idea is that it evaluates if the two objects satisfy some particular condition - in the example, if one is greater than the other.
You can create a predicate either by just defining a function with the correct signature
bool IsIntGreater(int First, int Second)
{
return First>Second;
}
and passing the name of the function as the argument (this will result in passing a function pointer), or creating a function object (a functor), i.e. an object which overloads the function call operator and thus can be used as a function; the std::greater<T> type is a template functor, and in your snippet a temporary object of type std::greater<int> is created and passed to the std::sort algorithm.
Functors have several advantages over functions, especially when they have to be passed as arguments, have a look here for more information about this.
See comp in http://www.cplusplus.com/reference/algorithm/sort/
It is the function that does the comparison.

Should I use functions or stateless functors?

These 2 piece of code do same thing. And it will be used in sort function as you can see.
Which is better? I usually write latter one. But I saw some coders do it like former one.
struct val_lessthan : binary_function<pair<string,int>, pair<string, int>, bool>
{
bool operator() (const pair<string,int>& x, const pair<string,int>& y) const
{
return x.second < y.second;
}
} val_lt;
and
bool val_lt(const pair<string,int>& x, const pair<string,int>& y)
{
return x.second < y.second;
}
Will use it like:
std::sort(wordvector.begin(), wordvector.end(), val_lt);
The reason you see some people prefer the first version is that functors can be trivially inlined.
When you pass a functor to std::sort, the functor type is known to the function, and so the exact function to call is also known at compile-time, and can be trivially inlined.
With a plain function, what std::sort really sees is just a function pointer, and at compile-time that says nothing about which function it points to. So that can't be inlined unless the compiler performs some fairly extensive flow analysis to see where the pointer came from in this specific call. And it will certainly do that optimization in a small example like yours, but if the functor/function pointer was passed in as a function argument from somewhere else, for example, or it was read from an intermediate data structure before being passed to std::sort, then, the compiler might not be able to inline the function pointer version, and so it would end up slower.
The first one is called a function object and is useful if you need to pass any context information to the comparison function. The standalone function only gets x and y and doesn't have the opportunity to carry along any context.
In the specific instance above, the two ways of writing the comparison function are roughly equivalent.
I'd probably prefer the first as a rule, but would generally prefer to use a template:
template <class T>
struct val_lessthan : binary_function<pair<pair<T, T>, bool> {
bool operator()(T const &x, T const &y) const {
return x.second < y.second;
}
};
Use of .second limits the degree of genericity, but you still get a little (e.g., if memory serves, boost::tuple provides a .first and .second for tuples of two elements. As a rule, being a template gives a little better assurance that the compiler will be able to generate the code inline, so if you care about efficiency, it might help a little (or it might not, but is unlikely to ever cause any harm).
If you want to be able to also call the function in other part of your code, and not passed as a functor, prefer the function form. For example you would prefer:
if (val_lt(a,b))
{
//...
}
to
if(val_lessthan()(a,b))
{
// ...
}
Otherwise when choosing the functor form, you'd better call with an unnamed functor object. That is:
std::sort(wordvector.begin(), wordvector.end(), val_lesstthan());
instead of:
val_lesstthan named;
std::sort(wordvector.begin(), wordvector.end(), named);
Unnaming parameters and return values easily enables the compiler to perform optimization. It refers to a global concept known as RVO (Return Value Optimization). In that case it will probably free your code from one copy construction.
I'd say, choose the simplest which works for your particular case. In this case, choose second over the first.
Both will be equally fast. Almost negligible difference.
When you use functor, it means the function operator() has three parameters in the code generated by the compiler, first paramater is a pointer to the val_lt object itself, and the second and third parameters are the parameters which you've mentioned in the signature. Something like this:
//the possible code generated by the compiler!
bool operator() (val_lessthan *_this, const pair<string,int>& x, const pair<string,int>& y) const
//^^^^^^^^^^^^^^^^^^^ note this!
{
return x.second < y.second;
}