在c++中实现类似sql的顺序

Implementing SQL-like order in C++

本文关键字:sql 顺序 c++ 实现      更新时间:2023-10-16

是否有一个算法在c++中排序多列?或者用其他方式,比如SQL用非常简单的方式,ORDER BY <>,<> ?例如,给定SQL SillyData表:

<>之前姓名年龄最喜欢的水果幸运数字--------------------------------------玛丽22苹果2爱丽丝22香蕉7Bob 21 Orange 8Mark 21 Apple 0约翰22香蕉3之前

当我做的时候SELECT * FROM SillyData ORDER BY Age, FavouriteFruet, LuckyNumber,这产生结果:

<>之前姓名年龄最喜欢的水果幸运数字--------------------------------------Mark 21 Apple 0Bob 21 Orange 8玛丽22苹果2约翰22香蕉3爱丽丝22香蕉7之前

我能想到的是一个listtuple s。但然后我必须按第一个tuple类型排序,锁定它的顺序,然后第二个,……等等......看起来又复杂又笨重。有更好的办法吗?

假设您希望对字符串进行不区分大小写的比较,这是一个起点:

#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';
    }    
}
预期输出:

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

您可以使用std::stable_sort。例如,我为类型info定义了不同的单独排序函数,并将它们与std::stable_sort一起使用,以实现我想要的任何相对排序:

struct info
{
    std::string name;
    int age;
    std::string fav_fruit;
    int fav_number;
    // static functions define sorting methods
    static bool sort_by_name(info const& lhs, info const& rhs)
    {
        return lhs.name < rhs.name;
    }
    static bool sort_by_age(info const& lhs, info const& rhs)
    {
        return lhs.age < rhs.age;
    }
    static bool sort_by_fav_fruit(info const& lhs, info const& rhs)
    {
        return lhs.fav_fruit < rhs.fav_fruit;
    }
    static bool sort_by_fav_number(info const& lhs, info const& rhs)
    {
        return lhs.fav_number < rhs.fav_number;
    }
    // friend function provides output operator
    friend std::ostream& operator<<(std::ostream& os, info const& i)
    {
        return os << i.name << 't' << i.age << 't' << i.fav_fruit << 't' << i.fav_number;
    }
};
int main()
{
    std::vector<info> infos
    {
        {"Mary",  22, "Apple",  2},
        {"Alice", 22, "Banana", 7},
        {"Bob",   21, "Orange", 8},
        {"Mark",  21, "Apple",  0},
        {"John",  22, "Banana", 3},
    };
    // std::stable_sort will not rearrange the currently sorted order
    // of items that are otherwise considered equal in terms of the current
    // sort condition
    // NOTE: We sort them in reverse order of importance, the most significant
    // ordering being the last one imposed
    std::stable_sort(infos.begin(), infos.end(), info::sort_by_fav_number);
    std::stable_sort(infos.begin(), infos.end(), info::sort_by_fav_fruit);
    std::stable_sort(infos.begin(), infos.end(), info::sort_by_age);
    std::cout << "NametAgetFruittNumber" << 'n';
    std::cout << "----t---t-----t------" << 'n';
    for(auto i: infos)
        std::cout << i << 'n';
}
输出:

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

您可能需要一些字典顺序。

所以使用std::lexicographical_compare可能传递给一些std::sort作为比较测试。

(我希望你至少使用c++ 11)