简体   繁体   English

C ++等同于Python的cmp或Haskell的比较

[英]C++ equivalent to Python's cmp or Haskell's compare

Question: 题:

Is there a C++ equivalent for Python's cmp or Haskell's compare ? 是否有C ++等效于Python的cmp或Haskell的compare

compare is like operator== and operator< in one. compare就像operator==operator<合而为一。 It returns LT , EQ , or GT . 它返回LTEQGT But it's twice as fast as calling both operator== and operator< because it does it in one pass. 但这是同时调用operator==operator<的两倍,因为它一次完成了。

More details: 更多细节:

At work, I often have structs that are used as keys for maps, for example: 在工作中,我经常有用作地图键的结构,例如:

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;
}

One problem with RecordUsedAsAKey::operator< is that it's unnecessarily slow. RecordUsedAsAKey::operator<一个问题是它的速度不必要地慢。

  • When the string::operator!= finds a different character, the program iterates over the equal characters again in the string::operator< , when it could have skipped those.. string::operator!=找到一个不同的字符时,程序可能会跳过这些字符时,再次在string::operator<迭代相同的字符。
  • Same for the vector 's comparison. vector的比较也一样。

If I had an equivalent to Haskell's compare , my comparison method would had been more efficient: 如果我具有与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);
}

This is more efficient because the string 's compare method does only one pass on the string. 这是更有效的方法,因为stringcompare方法仅对字符串执行一次传递。

Btw/mini-flame-war: in Haskell the whole code for the comparison would just be deriving Ord . Btw / mini-flame-war:在Haskell中,用于比较的整个代码只是deriving Ord

You can easily implement it yourself, as a free function. 您可以轻松地将其实现为免费功能。

#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;
}

Note: I edited the code to include a templated version for the general case (work provided that the operator< and operator== are defined for the type). 注意:我编辑了代码,以包括一般情况下的模板版本(只要为该类型定义了operator <和operator ==,就可以进行工作)。 I also kept some specialization as it can improve run time on some type (mainly containers). 我还保留了一些专业知识,因为它可以缩短某些类型(主要是容器)的运行时间。

Edit: Using std::string::compare instead of strcmp . 编辑:使用std::string::compare而不是strcmp

Since map semantics are in term of operator< , and that in fact many operators implementations are in term of operator< , probably something only in term of it is better. 由于map语义是用operator< ,并且实际上许多运算符实现都是用operator< ,所以可能仅以它为代表的更好。

For instance: 例如:

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;
}

or, better, 或更好,

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>());
}

so that you can use compare(k1, k2, mymap.key_comp()) if you need to. 因此,您可以根据需要使用compare(k1, k2, mymap.key_comp())

After your program works, and you are convinced that compare is the bottleneck , you can specialize for the offending types. 程序运行后, 您确信compare是瓶颈 ,因此您可以专门处理有问题的类型。 Do for instance 例如

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);
}

if you are worried about efficiency for string types. 如果您担心字符串类型的效率。

If you are comparing sequences, you can use std::lexicographical_compare . 如果要比较序列,则可以使用std::lexicographical_compare However, you may want to reimplement it to handle the equality case, here is an optimized version for std::vector : 但是,您可能需要重新实现它以处理相等情况,这是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;
}

simpler and more general version of Sylvain Defresne's answer: 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;
}

The std::string already has a compare member function that does what you want. std :: string已经具有执行所需功能的比较成员函数。

For other sequences, like std::vector, there is a std::mismatch function in <algorithm> that scans two sequences side-by-side and returns iterators to the first two elements that differ. 对于其他序列,例如std :: vector, <algorithm>中有一个std :: mismatch函数,该函数并排扫描两个序列,并将迭代器返回到不同的前两个元素。 From there, you only have to figure out if these two elements are less than or greater than each other. 从那里,您只需要确定这两个元素是否彼此小于或大于即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM