adiamond adiamond - 2 months ago 11
C++ Question

Implementing SQL-like order in C++

Is there an algorithm in c++ to sort by multiple columns? Or some other way like SQL does it in a very simple way,

ORDER BY <>,<>
? For example, given SQL SillyData table:


Name Age FavouriteFruet LuckyNumber
--------------------------------------
Mary 22 Apple 2
Alice 22 Banana 7
Bob 21 Orange 8
Mark 21 Apple 0
John 22 Banana 3


When I do
SELECT * FROM SillyData ORDER BY Age, FavouriteFruet, LuckyNumber
this yeilds the result:


Name Age FavouriteFruet LuckyNumber
--------------------------------------
Mark 21 Apple 0
Bob 21 Orange 8
Mary 22 Apple 2
John 22 Banana 3
Alice 22 Banana 7


All I can think of is a
list
of
tuple
s. But then I would have to sort by first
tuple
type, lock the order of it, then second, ...and so on. Looks complicated and cumbersome. Any better way?

Answer

assuming that you want a case-insensitive compare for the strings, this is a starting point:

#include <tuple>
#include <string>
#include <iostream>
#include <cstring>
#include <functional>

struct row
{
    std::string Name;
    int Age;
    std::string FavouriteFruet;
    int LuckyNumber;
};

auto index_order(const row& r)
{
    auto as_upper = [](std::string s)
    {
        std::transform(s.begin(), s.end(), s.begin(), [](auto c){return std::toupper(c); });
        return s;
    };
    return std::make_tuple(std::cref(r.Age), as_upper(r.FavouriteFruet), std::cref(r.LuckyNumber), as_upper(r.Name));
}

int main()
{
    std::vector<row> results =
    {
        { "Mary", 22, "Apple", 2},
        { "Alice", 22, "Banana", 7},
        { "Bob", 21, "Orange", 8},
        { "Mark", 21, "Apple", 0},
        { "John", 22, "Banana", 3},
    };

    std::sort(results.begin(), results.end(),
              [](auto const& l, auto const& r)
              {
                  return index_order(l) < index_order(r);
              });

    for (auto const& r : results)
    {
        std::cout << r.Name << " | " << r.Age << " | " << r.FavouriteFruet << " | " << r.LuckyNumber << '\n';
    }    
}

expected output:

Mark | 21 | Apple | 0
Bob | 21 | Orange | 8
Mary | 22 | Apple | 2
John | 22 | Banana | 3
Alice | 22 | Banana | 7