0

I'd like to write code using class double sorting(?).

For example, class has three data member i.e. num, error, and data.

class Test
{
public:
    int num;
    float error;
    vector<float> data;
};

Now, I make:

vector<Test> TestList;

and, those have:

TestList[0] : num = 1, error = 0.001, data0

TestList[1] : num = 1, error = 0.01, data1

TestList[2] : num = 2, error = 0.01, data2

TestList[3] : num = 3, error = 0.001, data3

TestList[4] : num = 3, error = 0.01, data4

Then, I want to sort them with num (higher priority) and error.
The expected result is the TestList is arranged as following order:

Test[4] : num = 3, error = 0.001, data4

Test[3] : num = 3, error = 0.01, data3

Test[2] : num = 2, error = 0.01, data2

Test[0] : num = 1, error = 0.001, data0

Test[1] : num = 1, error = 0.01, data1

How can I do this? In addition, how can I call this algorithm?

Azeem
  • 11,148
  • 4
  • 27
  • 40
Wooni
  • 481
  • 1
  • 3
  • 17
  • Look for a sort that is documented as a "stable" sort, then sort first by `error`, then `num`. e.g. mergesort is a stable sort algorithm. – wmorrell Aug 11 '17 at 06:01
  • 1
    Possible duplicate of [What's the simplest way of defining lexicographic comparison for elements of a class?](https://stackoverflow.com/questions/2500664/whats-the-simplest-way-of-defining-lexicographic-comparison-for-elements-of-a-c) – lisyarus Aug 11 '17 at 08:46

4 Answers4

2

The order you're referring to is called Lexicographical order

You could simply sort your vector<Test> with std::sort by providing either a suitable comparator, or by implementing operator<, as explained in Sorting a vector of custom objects

The last implementation could be something like:

class Test
{
public:
    int num;
    float error;
    vector<float> data;
    bool operator<( const X& val ) const
    { 
      if (num > val.num)
      {
        return true;
      }
      else if (num == val.num && error < val.error)
      {
        return true;
      }
      else
      {
        return false;
      }
    }
}
Lanting
  • 3,060
  • 12
  • 28
1
  1. Implement operator < in Test

    class Test {
    public:
        int num;
        float error;
        vector<float> data;
    
        bool operator < (const Test & val)const
        { 
          return num > val.num || num == val.num && error < val.error; 
        }
    };
    
  2. use std::sort to sort

    sort(TestList.begin(), TestList.end());
    
Discbrake
  • 315
  • 2
  • 14
Peng
  • 11
  • 1
  • I guess is a tipo: should be `num < val.num` with smaller not greater. – Adrian Maire Aug 11 '17 at 08:43
  • @AdrianMaire OP wants num sorted descending – Caleth Aug 11 '17 at 08:45
  • You cannot make a comparison operator to behave wrong/non-intuitive just for a single case of vector sorting: why if 20 line further you need another sorting but ascending? Use reverse iteration. – Adrian Maire Aug 11 '17 at 08:55
  • If you need to sort in another way, you can provide another comparison function to std::sort. Operator < is the default way. In this case, both are acceptable. – Peng Aug 14 '17 at 02:56
1

std::sort takes a comparer, so you can use:

std::vector<Test> tests /* = ...*/;

std::sort(tests.begin(), test.end(), [](const Test& lhs, const Test& rhs)
    {
        return std::tie(rhs.num, rhs.error) < std::tie(lhs.num, lhs.error);
    });
Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

You can use std::sort, and provide a comparison function object.

auto NumDescErrorAsc = [](const Test & lhs, const Test & rhs)
{ return std::tie(rhs.num, lhs.error) < std::tie(lhs.num, rhs.error); };
auto NumAscErrorAsc = [](const Test & lhs, const Test & rhs)
{ return std::tie(lhs.num, lhs.error) < std::tie(rhs.num, rhs.error); };

sort(TestList.begin(), TestList.end(), NumDescErrorAsc); // Required order

sort(TestList.begin(), TestList.end(), NumAscErrorAsc); // Original order

This works because std::tuple::operator< provides an ordering based on the first value, with later values breaking ties. Note how we use the right hand side num on the left in NumDescErrorAsc. That's equivalent to using > for num.

Caleth
  • 52,200
  • 2
  • 44
  • 75