首页 > 解决方案 > 将 std::set 与基于键的比较器一起使用

问题描述

假设我有一组字符串(或映射),并且我想使用一个自定义比较器,它只比较前 5 个字符。所以“abcde”和“abcdef”在我的集合中是一样的。

typedef std::set<std::string, Cmp> MySet;

编写 Cmp 的最佳方法是什么?

显而易见的方法是这样的:

struct Cmp
{
    bool operator()(const string& x, const string& y)
    {
        return (x.substr(0, 5) < y.substr(0, 5));
    }
}

问题是这段代码重复了.substr(0, 5)。在这个例子中它很短,但在一般情况下它可能会更长。我想避免这个重复的代码。

一般来说,给定 typesT1, T2和 function T2 key(T1& const),我想要一组T1根据 进行比较的元素key(a) < key(b),其中比较 onT2已经明确定义。写这个的最好方法是什么?我想过写一个新的class KeyBaseSet. ,但这对于我的单个用例来说是过度设计的。有没有办法使用std或 Boost 来做到这一点?

我正在寻找类似于key在 Python 中排序(https://docs.python.org/3/howto/sorting.html#key-functions)或compare `on` Haskell 中的成语(https://stackoverflow. com/a/2788262/351105)。

标签: c++

解决方案


您可以Cmp使用密钥策略进行自定义。最小的例子:

template<class Key>
struct Compare_on {
    Compare_on(Key key = Key()) : key_(key)
    {}

    template<class T>
    bool operator()(const T& x, const T& y) const {
        return key_(x) < key_(y);
    }

private:
    Key key_;
};

struct First3 {
    std::string_view operator()(const std::string& s) const {
        return std::string_view(s).substr(0, 3);
    }
};

// Example:
std::set<std::string, Compare_on<First3>> set;
set.insert("abc1");
set.insert("abc2");

演示


Compare_on可以通过使其成为透明比较器来改进:

template<class Key>
struct Compare_on {
    using is_transparent = void;

    Compare_on(Key key = Key()) : key_(key)
    {}

    template<class T1, class T2>
    bool operator()(const T1& x, const T2& y) const {
        return key_(x) < key_(y);
    }

private:
    Key key_;
};

struct First3 {
    template<class T>
    std::string_view operator()(const T& s) const {
        return std::string_view(s).substr(0, 3);
    }
};

现在当我们做

auto pos = set.find("abc");

std::string不会为字符串文字构造临时的"abc"

演示 2


推荐阅读