adiamond adiamond - 11 months ago 62
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 Source

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