结构上的ORDER BY的C ++实现

时间:2013-09-13 08:01:39

标签: c++ sorting boost stl compare

我在这里和其他网站上搜索了很多,但我还没有找到令人满意的东西。

我需要的是一项非常简单的任务 - 基本上可以在c ++中构造ORDER BY运算符。这意味着我有多个不同数据类型成员的结构,我需要一个比较器,成员和订单可配置。这是我的伪代码:

comparator.add(&MyStruct::member1, std::less);
comparator.add(&MyStruct::member2, std::greater);
std::sort(my_vector.begin(), my_vector.end(), comparator);

我获取按member1排序的数据,如果它等于member2则决定,依此类推。

我在stl和模板方面不太好,但我可以阅读并破译一些代码并发现这是非常合适的解决方案:https://stackoverflow.com/a/11167563

不幸的是,在我的工作中,我必须使用带有错误的32位编译器的c ++ builder,拒绝编译这个正确的代码。它确实support almost nothing from c++11,它提升了1.39。

有人有任何可用我的资源可以为我工作的解决方案吗?提前谢谢你

编辑:

我得到了非常专业的解决方案,其中包括我所知道的难以编写的比较运算符,这些运算符在这里不起作用。我在我的问题中错过了这个。我的结构至少有15个成员,正如我写的,我需要经常更改成员/列的单独排序方向(asc,desc)。我也需要经常更改已排序成员的集合,就像在sql中按运算符顺序一样。我也不能使用类似stable_sort的东西,因为我只是为某些类的OnCompare事件编写比较器。

3 个答案:

答案 0 :(得分:4)

这并不太难。首先,考虑“规范” 订购关系:

struct Compare
{
    bool operator()( C const& lhs, C const& rhs ) const
    {
        return lhs.a < rhs.a
            || ( !(rhs.a < lhs.a) && lsh.b < rhs.b )
            || ( !(rhs.a < lhs.a) && !(rhs.b < lhs.b) && lhs.c < rhs .c )
            || ...
    }
};

显然,没有人会写这样的东西,但是 它完全对应于什么的正式定义 需要的。

当然,如果我们可以把数据成员想象成一个数组,我们 可以将此重写为循环,利用之前的优势 在每种情况下建立!(rhs[i-1] < lsh[i-1]

struct Compare
{
    bool operator()( C const& lhs, C const& rhs ) const
    {
        int i = 0;
        while ( i != N && !(lhs[i] < rhs[i]) && !(rhs[i] < lhs[i]) ) {
            ++ i;
        }
        return i != N && lhs[i] < rhs[i];
    }
};

或者,如果所有元素都是完全有序的,那么==就是。{1}} 也定义了它们,我们可以假设它对应于 弱部分建立的等价关系 排序:

struct Compare
{
    bool operator()( C const& lhs, C const& rhs ) const
    {
        int i = 0;
        while ( i != N && !(lhs[i] == rhs[i]) ) {
            ++ i;
        }
        return i != N && lhs[i] < rhs[i];
    }
};

剩下的就是以某种方式将其转化为某种东西 可以处理任意元素的任意排序 类型。有句老话说解决每一个问题 是一个额外的间接层,它适用于此。

首先,我们需要一些处理不同类型的方法 每个元素。多态性似乎是合适的(尽管如此) 模板可以用来如果的顺序 评估的元素在编译时固定):

struct CompareOneElementOfC
{
    virtual bool isLessThan( C const& lhs, C const& rhs) const = 0;
    virtual bool isEqual( C const& lhs, C const& rhs) const = 0;
};

template <typename T, T C::*ptr>
struct ConcreteCompareOneElementOfC : public CompareOneElementOfC
{
    virtual bool isLessThan( C const& lhs, C const& rhs) const
    {
        return lhs.*ptr < rhs.*ptr;
    }
    virtual bool isEqual( C const& lhs, C const& rhs) const
    {
        return lhs.*ptr == rhs.*ptr;
    }
};

根据元素的类型,您可能需要提交 写具体的具体实例。如果有任何元素 不支持总排序,你将不得不省略 isEqual,并相应地修改以下代码。

到目前为止,我们只需要一个静态实例 具体比较:

ConcreteCompareOneElementOfC<int, &C::a> const c1;
ConcreteCompareOneElementOfC<double, &C::b> const c2;
//  ...

最后,将这些实例的地址放在表格中:

CompareOneElementOfC const* const cmp[] = { &c1, &c2 ... };

您可以为不同的排序设置不同的表格。如果有 只有少数,为每个定义静态表,并完成 它。如果排序可以是任意的,请在上面创建表 在每种排序之前按所需顺序飞行。

最后:

class Compare
{
    CompareOneElementOfC const* const* begin;
    CompareOneElementOfC const* const* end;
public:
    template< size_t N >
    Compare( CompareOneElementOfC const* const (&cmp)[N] )
        : begin( cmp )
        , end( cmp + N )
    {
    }
    bool
    operator()( C const& lhs, C const& rhs ) const
    {
        auto current = begin;
        while ( current != end && (*current)->isEqual( lhs, rhs ) ) {
            ++ current;
        }
        return current != end && (*current)->isLessThan( lhs, rhs );
    }
}

(请注意我实际上没有测试过这段代码,所以那里 可能是拼写错误和其他错误。仍然是基本的想法 应该在那里。)

答案 1 :(得分:1)

我认为只是重载operator <会对你有用。

struct Struct {
    int member1;
    int member2;

    bool operator<(const Struct& rhs) const {
        if (member1 != rhs.member1)
            return member1 < rhs.member1
        else
            return member2 > rhs.member2
    }
};

这样,只要比较Struct的任何2个实例,它们就会被operator <中定义的比较函数进行比较。

这样一个简单的std::sort(vec.begin(), vec.end())就可以了!

修改

否则,您始终可以定义一个可用于比较每个元素的仿函数。这只是一个带有重载operator ()的类,用于比较。

class ComparisonClass {
public:
    bool operator()(const Struct& lhs, const Struct& rhs) {
        if (lhs.member1 != rhs.member1)
            return lhs.member1 < rhs.member1
        else
            return lhs.member2 > rhs.member2
    }
};

您还可以定义ComparisonClass的一些成员值,用于定义比较顺序。

使用它会像std::sort(vec.begin(), vec.end(), ComparisonClass());

那样调用它

EDIT2:

稍微复杂一点的代码 -

class ComparisonClass {
public:
    bool operator()(const Struct& lhs, const Struct& rhs) {
        for(int i=0; i<m_comparisonOrder.size(); i++) {
            int pos = m_comparisonOrder[i];
            if (lhs[pos] != rhs[pos]) {
                if (m_comparisonType[pos])
                    return lhs[pos] < rhs[pos];
                else
                    return lhs[pos] > rhs[pos];
            }
        }
    }

    std::vector<int> m_comparisonOrder.
    std::vector<bool> m_comparisonType;
};

这里我假设Struct有一个operator [],它返回相应的成员变量。

答案 2 :(得分:0)

为什么没有专门的比较器功能,首先检查member1,如果相等,则检查member2

bool comparator(const MyStruct& s1, const MyStruct& s2)
{
    if (s1.member1 == s2.member1)
        return s1.member2 > s2.member2;
    else
        return s1.member1 < s2.member1;
}