Reputation: 205
I have to sort a vector of structs. Let's say the struct has two members:
Struct game
{
string name;
int rating;
};
So I have created a std::vector<game>
games and simple sort them by rating.
std::sort(games.begin(),games.end(), [](game& info1, game& info2)
{
return info1.rating > info2.rating;
});
Everything is alright so far. The problem is if all games have rating value 0, they mix. Simply put I have to sort only elements with rating bigger than zero. Let's give you an example:
All games are pushed in the vector by names in alphabetic order and rating 0, when a sort is triggered, the alphabet order gets violated.
Example before sort:
"A_Game"
, "B_Game"
, "C_Game"
, "E_Game"
, "G_Game"
, etc. (continue with all next letters)
after sort (all games are with rating 0):
"G_Game"
, "S_Game"
, "P_Game"
, "M_Game"
, "L_Game"
, "I_Game"
, etc.
I need to sort only these games that have rating bigger than 0. Thanks in advance.
Upvotes: 4
Views: 189
Reputation: 11317
std::sort
indeed doesn't guarantee any ordering for when elements compare equal. std::stable_sort
guarantees that the original ordering gets kept if it compares equal. (See the other answers)
When in doubt about the original order, I like to explicitly sort with all of the criteria:
std::sort(games.begin(),games.end(), [](game const & info1, game const & info2)
{
if (info1.rating != info2.rating)
return info1.rating > info2.rating;
return info1.name < info2.name;
});
In the above, I prefer to use the following pattern
if member1 different
return compare member1
if member2 different
return compare member2
return compare member<last> OR compare pointers
This pattern is easily recognizable and easy extendable when you add extra members.
Ideally, when you want to use this sorting at other places, you make this a function with an unambiguous name. (Don't use operator<
as this causes confusion, since the game titles could as well be used as a logical way of sorting)
Upvotes: 1
Reputation: 11174
You can use stable_sort
instead of sort
. This would be the best option for the question.
You can also modify the sort so that when two games have equal rating, sort alphabetically comparing the two names (or any other condition that might come up in the future). It might look like this.
std::sort(games.begin(),games.end(), [](game& info1, game& info2)
{
if (info1.rating == info2.rating)
return info1.name.compare(info2.name);
return info1.rating > info2.rating;
});
Upvotes: 1
Reputation: 773
You can use std::stable_sort()
.
However, you can keep using std::sort()
and make the comparator return true
for games with the same rating (so the relative order is kept), by changing the condition to
return !(info1.rating < info2.rating)
Upvotes: 2
Reputation: 24788
std::sort()
is not a stable sorting algorithm, i.e., elements with equivalent keys may not preserve the original order between them after being sorted.
You can use std::stable_sort()
instead of std::sort()
:
std::stable_sort(games.begin(),games.end(), [](game& info1, game& info2)
{
return info1.rating > info2.rating;
});
As its name already suggest, std::stable_sort()
implements a stable sorting algorithm.
Upvotes: 5
Reputation: 93334
You can use std::stable_sort
to prevent moving around elements that are not affected by the sorting criteria.
std::stable_sort(games.begin(),games.end(), [](game& info1, game& info2)
{
return info1.rating > info2.rating;
});
Upvotes: 11