簡體   English   中英

C ++等同於Python的cmp或Haskell的比較

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

題:

是否有C ++等效於Python的cmp或Haskell的compare

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

這是更有效的方法,因為stringcompare方法僅對字符串執行一次傳遞。

Btw / mini-flame-war:在Haskell中,用於比較的整個代碼只是deriving Ord

您可以輕松地將其實現為免費功能。

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

注意:我編輯了代碼,以包括一般情況下的模板版本(只要為該類型定義了operator <和operator ==,就可以進行工作)。 我還保留了一些專業知識,因為它可以縮短某些類型(主要是容器)的運行時間。

編輯:使用std::string::compare而不是strcmp

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

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

std :: string已經具有執行所需功能的比較成員函數。

對於其他序列,例如std :: vector, <algorithm>中有一個std :: mismatch函數,該函數並排掃描兩個序列,並將迭代器返回到不同的前兩個元素。 從那里,您只需要確定這兩個元素是否彼此小於或大於即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM