C ++相当于Python的cmp或Haskell的比较

时间:2011-03-10 09:56:58

标签: c++ python haskell

问题:

Python的cmp或Haskell的compare是否有C ++等价物?

compare就像operator==operator<一样。它会返回LTEQGT。但它的速度是调用operator==operator<的两倍,因为它会在一次传递中完成。

更多详情:

在工作中,我经常使用用作地图键的结构,例如:

struct RecordUsedAsAKey {
    int field_a;
    string field_b;
    vector<float> field_c;

    // operator< is needed for keys in maps.
    bool operator<(const RecordUsedAsAKey& other) const;
};

bool RecordUsedAsAKey::operator<(const RecordUsedAsAKey& other) const {
    if (field_a != other.field_a)
        return field_a < other.field_a;
    if (field_b != other.field_b)
        return field_b < other.field_b;
    return field_c < other.field_c;
}

RecordUsedAsAKey::operator<的一个问题是它不必要地慢。

  • string::operator!=找到不同的字符时,程序会在string::operator<中再次迭代相同的字符,当它可以跳过那些字符时..
  • vector的比较相同。

如果我有一个等同于Haskell的compare,我的比较方法会更有效率:

Ordering RecordUsedAsAKey::compare(const RecordUsedAsAKey& other) const {
    Ordering t;
    if ((t = field_a.compare(other.field_a)) != EQ)
        return t;
    if ((t = field_b.compare(other.field_b)) != EQ)
        return t;
    return field_c.compare(other.field_c);
}

这样效率更高,因为string的{​​{1}}方法只会对字符串进行一次传递。

Btw / mini-flame-war:在Haskell中,比较的整个代码只是compare

4 个答案:

答案 0 :(得分:3)

您可以自己轻松地实现它,作为一个免费功能。

#include <string>
#include <vector>
enum order {
    order_lt = -1,
    order_eq,
    order_gt
};

// General case, templated version.
template < typename T >
order compare(T left, T right) {
    if (left < right)
        return order_lt;
    if (left == right)
        return order_eq;
    return order_gt;
}

// Specialization
order compare(const std::string& left, const std::string& right) {
    return order(left.compare(right));
}
template < typename T >
order compare(const std::vector<T>& left, const std::vector<T>& right) {
     order o = compare(left.size(), right.size());
     if (o != order_eq)
         return o;
     for (size_t i = 0; i < left.size(); ++ i) {
         o = compare(left[i], right[i]);
         if (o != order_eq)
             return o;
     }
     return order_eq;
}

注意:我编辑了代码以包含一般情况的模板化版本(提供的操作符&lt;和operator ==为类型定义)。我还保留了一些专业化,因为它可以改善某些类型(主要是容器)的运行时间。

修改:使用std::string::compare代替strcmp

答案 1 :(得分:2)

由于map语义是operator<的术语,实际上许多运算符的实现都是operator<,所以可能只有它的一部分更好。

例如:

template <typename T>
int compare(const T& x, const T& y)
{
    if (x < y) return -1;
    else if (y < x) return 1;
    else return 0;
}

或者更好,

template <typename T, typename F>
int compare(const T& x, const T& y, F pred)
{
    if (pred(x, y)) return -1;
    else if (pred(y, x)) return 1;
    else return 0;
}

template <typename T>
int compare(const T& x, const T& y)
{
    return compare(x, y, std::less<T>());
}

以便您可以根据需要使用compare(k1, k2, mymap.key_comp())

在您的程序运行后,并且您确信compare是瓶颈,您可以专门针对违规类型。例如

template <typename C, typename T, typename A>
int compare(const std::basic_string<C, T, A>& x,
            const std::basic_string<C, T, A>& y)
{
    return x.compare(y);
}

如果您担心字符串类型的效率。

如果您要比较序列,可以使用std::lexicographical_compare。但是,您可能希望重新实现它以处理相等的情况,这是std::vector的优化版本:

template <typename T, typename A, typename F>
int compare(const std::vector<T, A>& x,
            const std::vector<T, A>& y, F pred)
{
    std::vector<T, A>::const_iterator i = x.begin();
    std::vector<T, A>::const_iterator j = y.begin();

    while (i != x.end())
    {
        if (j == y.end()) return 1;
        if (pred(*i, *j)) return -1
        else if (pred(*j, *i)) return 1;

        ++i; ++j;
    }

    return j == y.end() ? 0 : -1;
}

答案 2 :(得分:1)

Sylvain Defresne答案的更简单和更一般的版本:

template<typename T>
order compare(const T &left, const T &right) {
    if (left < right)
        return order_lt;
    else if (left == right)
        return order_eq;
    return order_gt;
}

答案 3 :(得分:1)

std :: string已经有了一个比较成员函数,可以完成你想要的任务。

对于其他序列,如std :: vector,<algorithm>中有一个std :: mismatch函数,它并排扫描两个序列,并将迭代器返回给前两个不同的元素。从那里,你只需要弄清楚这两个元素是否小于或大于彼此。