Is std::pair int, std::string ordering well-defined?
std::pair
uses lexicographic comparison: It will compare based on the first element. If the values of the first elements are equal, it will then compare based on the second element.
The definition in the C++03 standard (section 20.2.2) is:
template <class T1, class T2>
bool operator<(const pair<T1, T2>& x, const pair<T1, T2>& y);
Returns: x.first < y.first || (!(y.first < x.first) && x.second < y.second).
Comparison function for sorting std::set std::pair int,std::pair int,int
Your comparison function is a good start. What is missing is "tie resolution". You need to specify what happens when l.second.second == r.second.second
, and also what happens when l.second.first == r.second.first
:
bool operator()(const myPair& l, const myPair& r)const{
return (l.second.second < r.second.second) ||
((l.second.second == r.second.second) && (l.second.first < r.second.first)) ||
((l.second.second == r.second.second) && (l.second.first == r.second.first) && (l.first < r.first)).
}
- The first condition comes from your implementation.
- The second condition tells what to do when the first-priority items are equal to each other
- The third condition tells what to do when both the first-priority and the second-priority items are equal to each other.
In order to use this function for ordering your set, you need to pass it as the second template parameter to std::set
. Here is a Q&A explaining how to do it.
What is wrong with my comparison function?
You haven't explained how you want to sort your triples, so all I can say is that your expectations are wrong.
Your comparison function considers your last three elements to be equal.
A triple (x0,x1,x2)
is considered less than another triple (y0,y1,y2)
if x0 < y0
and x1 < y1
. For example, when comparing (6,4,7)
and (6,5,4)
, neither triple is considered less than the other because the first number in each triple is the same (6 < 6
is false). Similarly, (5,4,6)
is considered equal to (6,4,7)
because neither is less than the other (4 < 4
is false).
The only thing you might reasonably expect is that (5,4,6) < (6,5,4)
, but your comparison function also says both of those are equal to (6,4,7)
. In other words, the function claims there are values a
, b
, c
where a = b
and b = c
but a < c
. This makes no sense, so your comparison function is broken.
If all you want is a lexicographical ordering, you don't need to do anything special:
std::sort(vec.begin(), vec.end());
std::pair
sorts by its first component first; if those are equal, it compares the second components. That seems to be exactly the behavior you expect.
sorting a key-value pair according to values as well as keys
There is a similar question on HackerEarth This is how I solved it:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<std::pair<std::string, long>> hotels;
long n = 0;
std::cin >> n;
while (n--) {
std::pair<std::string, long> hotel;
std::cin >> hotel.first >> hotel.second;
hotels.push_back(hotel);
}
std::sort(hotels.begin(), hotels.end(), [](std::pair<std::string, long> lhotel, std::pair<std::string, long> rhotel)->bool {
if (lhotel.second > rhotel.second)
return true;
else if ((lhotel.second == rhotel.second) && (lhotel.first < rhotel.first))
return true;
return false;
});
std::cout << hotels.front().first;
return 0;
}
In your solution, just use vector instead of set and all will be fine :)
Just for future references, if you want to deviate from the standard implementation of
any STL container in c++, always go for vectors instead. Never fails ;)
how to use std::pair as the key std::map
Yes, it is allowed.
std::pair
already has an operator<
which compares the two values in order, so you may not need to do anything special for a comparator at all.
std::pair with a comparable and a non-comparable object needs to be sorted
Your wrapper class should be similar to:
template <typename T>
struct Wrapper{
Wrapper(const T & pair): pair_mem(pair) {}
bool operator <(const Wrapper& rhs) const {
return pair_mem.first < rhs.pair_mem.first;
}
T pair_mem;
};
Demo
But using custom comparer seems better (less intrusive).
std::sort(x.begin(), x.end(),
[](const auto& lhs, const auto& rhs) {
return lhs.first < rhs.first;
});
Related Topics
Does Static Constexpr Variable Inside a Function Make Sense
What Is Better, Adjacency Lists or Adjacency Matrices for Graph Problems in C++
Should I Store Entire Objects, or Pointers to Objects in Containers
How to Have Swift, Objective-C, C and C++ Files in the Same Xcode Project
Efficient Thread-Safe Singleton in C++
What Does "#Pragma Comment" Mean
Understanding Recursion to Generate Permutations
How to Properly Use Std::String on Utf-8 in C++
C++ HTML Template Framework, Templatizing Library, HTML Generator Library
How to Hook Windows Functions in C/C++
Standard Library Containers with Additional Optional Template Parameters
Child Process Receives Parent's Sigint
Cin for an Int Inputing a Char Causes Loop That Is Supposed to Check Input to Go Wild
C++11: the Range-Based for Statement: "Range-Init" Lifetime
C++ New Operator Thread Safety in Linux and Gcc 4
Why Don't the C or C++ Standards Explicitly Define Char as Signed or Unsigned