Since your comparison function is quite complex, I've rewritten it very verbosely, so each possible case can be inspected separately. I've also separated into a different function the decision about which partition of the output each element goes into.
#include <algorithm>
#include <iostream>
#include <iterator>
int classify(int const i)
{
if (i%3==0 && i%2!=0) {
return 1;
}
else if (i%3!=0) {
return 2;
}
else {
return 3;
}
}
bool comp(int const a, int const b)
{
int const a_part = classify(a);
int const b_part = classify(b);
if (a_part==1) {
if (b_part==1) {
// both in first partition, order ascending
return a<b;
}
else {
// a in first partition, b not, so a always first
return true;
}
}
else if (a_part==2) {
if (b_part==1) {
// b comes before a
return false;
}
else if (b_part==2) {
// both in middle partition, order ascendingly
return a<b;
}
else {
// a in middle partition, b in last partition, so a always first
return true;
}
}
else { // (a_part==3)
if (b_part!=3) {
// a in last partition, b in first or middle partition,
// so b always comes first
return false;
}
else {
// both in last partition, order descending
return b<a;
}
}
}
int main()
{
int ar[8] = {18 ,5 ,24 ,9 ,12 ,6 ,2, 3};
std::sort(std::begin(ar),
std::end(ar),
comp);
std::copy(std::begin(ar),
std::end(ar),
std::ostream_iterator<int>(std::cout,
"\n"));
}
Output:
$ ./SO
3
9
2
5
24
18
12
6
Bear in mind your comparator must induce a Strict Weak Ordering, which I think this does, but it's a bit trickier than one would normally use for sorting.
Always write your code as clearly as possible, not as short as possible. If you have some complicated logic, break it up, move parts out into functions, and add plenty of comments. Remember, other people have to read and understand it, including yourself in 6 months.
What might be a better approach is to split the sort up. You are really talking about splitting the array into 3 partitions, each being treated differently. So use std::partition
twice, and std::sort
three times. I think that may well be more understandable. This code has the exact same output as the above:
bool isOddMultipleOfThree(int const i)
{
return (i%3==0 && i%2!=0);
}
bool isEvenMultipleOfThree(int const i)
{
return (i%3==0 && i%2==0);
}
int main()
{
int ar[8] = {18 ,5 ,24 ,9 ,12 ,6 ,2, 3};
// split off the first partition
auto firstSplit = std::partition(std::begin(ar),
std::end(ar),
isOddMultipleOfThree);
// sort the first partition
std::sort(std::begin(ar),
firstSplit,
std::less<int>());
// split off end partition
// use a lambda to invert the predicate, because we want the matching
// values pushed to the end
auto secondSplit = std::partition(firstSplit,
std::end(ar),
[](int const i) {
return !isEvenMultipleOfThree(i);
});
// sort middle partition
std::sort(firstSplit,
secondSplit,
std::less<int>());
// sort last partition
std::sort(secondSplit,
std::end(ar),
std::greater<int>());
// print
std::copy(std::begin(ar),
std::end(ar),
std::ostream_iterator<int>(std::cout,
"\n"));
}
Also worth mentioning, many people (myself included) consider using namespace std;
and std::endl
are bad practices.