Reputation: 1019
In my hypothetical app, I receive a list of hotels from the server.
struct Hotel
{
std::string name; // e.g. Hilton, Ritz
int stars; // In range [0..5], 0 stands for "unrated"
int freeRoomCount; // Number of available rooms [0..N]
int parkingPlacesAvailable; // Number of parking places availalble [0..M]
}
std::vector<Hotel> hotels;
All these items are displayed in a simple List View.
I have to provide different types of sorting. The sorting rules are also dictated by the central server.
The sorting rules are as follows:
std::string sortingRules;
// "s" - sort by stars count
// "f" - sort by free room count
// "p" - sort by parking places available
// The sortingRules string can be a combination of those values. E.g.:
// "ps" - first goes who has the most number of parking places available,
// then goes hotels who has more stars
// More combinations available:
// "s", "sf", "fp", "pf", "spf", "" etc.
// (16 possible combinations, the empty string means alphabetical sorting)
So the question is: how to interpret this in C++? Enums and bit mask values doesn't work since they do not provide the 'order' control.
I am curious how would the community solve this kind of task? I feel like there is an approach for solving this type of problem, that's why I don't want to go straightforward and write code like:
if (sortingRules[0] == "s") ...
I am using C++11 along with Qt 5.4. No boost.
Upvotes: 2
Views: 328
Reputation: 117876
You can make a map between their choice and a functor to sort by, for example
using SortFun = bool(*)(Hotel const&, Hotel const&);
std::map<char, SortFun> sorters {
{'s', [](Hotel const& lhs, Hotel const& rhs){ return lhs.stars < rhs.stars; }},
{'f', [](Hotel const& lhs, Hotel const& rhs){ return lhs.freeRoomCount < rhs.freeRoomCount; }},
{'p', [](Hotel const& lhs, Hotel const& rhs){ return lhs.parkingPlacesAvailable < rhs.parkingPlacesAvailable; }}
};
Then you can use it by asking the user to input the sort criteria key, and then you can lookup the correct lambda to sort by using std::stable_sort
. For the combinations of sort criteria, e.g. "ps"
, you can loop over each sort key and std::stable_sort
consecutively in reverse order.
int main()
{
using SortFun = bool(*)(Hotel const&, Hotel const&);
std::map<char, SortFun> sorters {
{'s', [](Hotel const& lhs, Hotel const& rhs){ return lhs.stars < rhs.stars; }},
{'f', [](Hotel const& lhs, Hotel const& rhs){ return lhs.freeRoomCount < rhs.freeRoomCount; }},
{'p', [](Hotel const& lhs, Hotel const& rhs){ return lhs.parkingPlacesAvailable < rhs.parkingPlacesAvailable; }}
};
std::vector<Hotel> hotels {{"foo", 5, 4, 10},
{"bar", 3, 8, 20},
{"baz", 4, 5, 15},
{"fab", 3, 6, 18}};
std::string choice;
std::cout << "Pick a sort criteria s, f, p: ";
std::cin >> choice;
for (auto rit = choice.rbegin(); rit != choice.rend(); ++rit)
{
auto match = sorters.find(*rit);
if (match != sorters.end())
{
std::stable_sort(begin(hotels), end(hotels), match->second);
}
}
for(auto const& hotel : hotels)
{
std::cout << "Name: " << hotel.name << " Stars: " << hotel.stars << " Rooms: " << hotel.freeRoomCount << " Parking: " << hotel.parkingPlacesAvailable << std::endl;
}
}
The output would be (working demo)
Pick a sort criteria s, f, p: sf
Name: fab Stars: 3 Rooms: 6 Parking: 18
Name: bar Stars: 3 Rooms: 8 Parking: 20
Name: baz Stars: 4 Rooms: 5 Parking: 15
Name: foo Stars: 5 Rooms: 4 Parking: 10
To sort from highest to lowest, just switch all the <
to >
in the lambda functions.
Upvotes: 2
Reputation: 2369
I'd use a simple parser that reads a character, applies an std::stable_sort
with the character's associated comparison predicate and proceeds to the next character.
The stable_sort part is really important. This means that if you sort the items by star count first, then by parking space, the order of star count will remain.
Upvotes: 3