Home > Blockchain >  How to sort the date in dd-mm-yyyy format in c
How to sort the date in dd-mm-yyyy format in c

Time:02-11

Suggest way to store and sort in c .

input:

01-02-2022
15-01-2022
20-10-2021
25-12-2022

CodePudding user response:

If you want to sort the dates represented as strings, you will have to parse the strings to order the dates chronologically. You can do this in-flight, if you don't need the parsed dates, or you can first parse all dates and then operate on the parsed data.

I'll show an example that does parsing in-flight, splitting the parsing and ordering parts is an exercise for the reader.

void sort_dates(std::vector< std::string >& dates)
{
    std::sort(dates.begin(), dates.end(),
        [](std::string const& left, std::string const& right)
        {
            // Parse dates
            unsigned int ly, lm, ld;
            if (std::sscanf(left.c_str(), "%u-%u-%u", &ld, &lm, &ly) != 3)
                throw std::invalid_argument("Date is in invalid format: "   left);

            unsigned int ry, rm, rd;
            if (std::sscanf(right.c_str(), "%u-%u-%u", &rd, &rm, &ry) != 3)
                throw std::invalid_argument("Date is in invalid format: "   right);

            // Compare the dates chronologically: return true if left < right
            if (ly < ry)
                return true;
            else if (ly > ry)
                return false;

            if (lm < rm)
                return true;
            else if (lm > rm)
                return false;

            return ld < rd;
        }
    );
}

CodePudding user response:

Slightly based off Andrey Semashev 's answer, you could parse and then store the date into a struct with a constructor taking a string input and having a less than operator for sorting, like so:

#include <algorithm> // for std::less
#include <string>
#include <tuple>     // for std::tie
#include <vector>

struct date
{
    unsigned int y, m, d;
    
    date(const std::string& date_str) : y(0), m(0), d(0)
    {
        if (std::sscanf(date_str.c_str(), "%u-%u-%u", &d, &m, &y) != 3)
            throw std::invalid_argument("Date is in invalid format: "   date_str);
    }
    
    friend bool operator< (const date& lhs, const date& rhs)
    {
        // Check years first, then months, then days
        return std::tie(lhs.y, lhs.m, lhs.d) < std::tie(rhs.y, rhs.m, rhs.d);
    }
};

void sort_dates(std::vector< std::string >& dates)
{
    // Requires an implicit constructor.
    // A lambda would be simple to write as an alternative.
    std::sort(dates.begin(), dates.end(), std::less<date>{});
}

CodePudding user response:

I would probably convert the strings to time_t's, and sort those. A time_t lets you represent the time with a single, easy to sort thing. Up to you whether to keep the original string with that time_t, or just convert back to the required format of string when you need it back.

#include <iostream>
#include <vector>
#include <chrono>
#include <sstream>
#include <iomanip>

class Date {
    tm expanded;
    time_t compact;
public:
    bool operator<(Date const& other) const {
        return compact < other.compact;
    }

    friend std::istream &operator>>(std::istream &is, Date &d) {
        is >> std::get_time(&d.expanded, "%d-%m-%Y");
        d.compact = mktime(&d.expanded);
        return is;
    }

    friend std::ostream &operator<<(std::ostream &os, Date const &d) {
        return os << std::put_time(&d.expanded, "%d-%m-%Y");
    }
};

int main() {
    std::istringstream input {
    R"(01-02-2022
    15-01-2022
    20-10-2021
    25-12-2022)"};

    std::vector<Date> dates { std::istream_iterator<Date>(input), {}};
    std::sort(dates.begin(), dates.end());
    std::copy(dates.begin(), dates.end(), std::ostream_iterator<Date>(std::cout, "\n"));
}

Result:

20-10-2021
15-01-2022
01-02-2022
25-12-2022
  • Related