c++sorting

custom comparitor for integers in string vector


I want to sort a vector of strings representing very large (10**6 digits) in ascending order in C++. I am trying to use a custom comparitor, but the sort is failing when comparing numbers of the same number of digits, eg. failing to re-arrange 82 and 44.

Here is a small example:

#include <bits/stdc++.h>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

string ltrim(const string &);
string rtrim(const string &);

bool comp(const string &left, const string &right)
{
    if (left.size() < right.size())
    {
        return true;
    }
    if (left.size() > right.size())
    {
        return false;
    }

    for (unsigned long int i = 0; i < left.size(); i++)
    {
        if (left[i] > (right[i]))
        {
            // left is bigger
            return false;
        }
    }
    // left is smaller or equal
    return true;
}

int main(void)
{
    vector<string> str_nums = {"82", "44", "131", "2"};

    sort(str_nums.begin(), str_nums.end(), comp);

    for (string e : str_nums)
    {
        cout << e << endl;
    }
    return 0;
}

This outputs:

2
82
44
131

where the numbers with different digits are fine, but those with two digits are not sorted. What is the issue, please?


Solution

  • You aren't returning true when you see a larger digit in right, so the later smaller digit is compared and false is returned. N.b. you are not meeting the requirements for std::sort, as returning true when things compare equal is invalid, you need a strict less than.

    bool comp(const string &left, const string &right)
    {
        if (left.size() < right.size())
        {
            return true;
        }
        if (left.size() > right.size())
        {
            return false;
        }
    
        for (unsigned long int i = 0; i < left.size(); i++)
        {
            if (left[i] > (right[i]))
            {
                // left is bigger
                return false;
            }
            if (left[i] < right[i])
            {
                // right is bigger
                return true;
            }
        }
        // left is equal
        return false;
    }
    

    See it on coliru

    However there is a much easier way of doing this comparison, which is to construct a std::tuple of each thing you want to compare, in the order of priority

    bool comp(const string &left, const string &right)
    {
        return std::forward_as_tuple(left.size(), left) < std::forward_as_tuple(right.size(), right);
    }