我给了一个std::set<std::pair<int,int>>
和一个整数x
,我必须找到第一个对的迭代器,它的第一个元素大于或等于给定的整数x
。
我了解到,如果s
是set<pair<int, int>>
,而{x, y}
是一对,那么我可以使用s.lower_bound({x, y})
。但是,就我而言,我只需要关心第一个元素x
。因此,我的问题是,当我只关心第一个元素时,如何在lower_bound
上使用set<pair<int, int>>
?
答案 0 :(得分:5)
核心问题是您的std::set
实例已经排序,但默认值为std::pair
operator<
。您不能直观地使用成员函数std::set::lower_bound
,因为它使用了其类类型的比较函数。您不能将std::lower_bound
与自定义谓词一起使用,因为它假定了排序范围-而是针对给定谓词进行了排序,并非如此。
但是对于这种特定情况,有一种解决方法。请注意,对于集合中每个x
的值,y
的最小关联值是类型int
的最小值。当std::pair
实例的比较运算符进行成员比较时,您可以将其组合为:
#include <set>
#include <limits>
const std::set<std::pair<int,int>> s{
{42, 0}, {42, 1}, {43, 0}, {43, 1}
};
const auto entry = s.lower_bound({43, std::numeric_limits<int>::min()});
这将始终在子集中找到与std::pair::first
数据成员的给定值相对应的 first 或 minimum 所需的条目。只有第一个值才有意义,因为第二个值立即不小于 std::numeric_limits<int>::min()
,这就是lower_bound
正在搜索的内容。
如果您多次需要此功能,可能值得将其放入自己的帮助器功能(模板)中,例如
template <class T>
auto lower_bound_first(const std::set<std::pair<T, T>>& s, T first)
{
static constexpr T min = std::numeric_limits<T>::min();
return s.lower_bound({first, min});
}
您可以调用为
const auto entry = lower_bound_first(s, 43);
适用于std::numeric_limits
专长专用的任何基础值类型。
答案 1 :(得分:1)
有一种方法无需构造临时pair
。一个需要的是在该对和另一种类型之间定义operator<
。为了避免弄乱operator<
和pair
的{{1}}的全局定义,请为包装器定义它:
int
这对于template <class T>
struct Wrapper
{
T value;
};
template <class T>
bool operator<(const std::pair<T, T> & x, Wrapper<T> value) {
return x.first < value.value;
}
template <class T>
bool operator<(Wrapper<T> value, const std::pair<T, T> & x) {
return value.value < x.first;
}
int main()
{
// NOTE: using std::less<>, instead of the default std::less<std::pair<int, int>>
std::set<std::pair<int, int>, std::less<>> s {{1,2}, {1,3}, {4,1}, {5,1}, {5,2}};
Wrapper<int> x{2};
auto it = s.lower_bound(x);
来说是一个矫kill过正,但是对于像std::pair<int, int>
这样的更复杂的类型,构造尽可能小的对象可能会很昂贵。另外,对于无限精度数字,不存在这样的值。在这种情况下,必须采用上述技术。对于更复杂的类型,可以简单地重载std::pair<int, MyFancyClass>
,而无需使用包装器。
请注意,重载的运算符必须彼此一致。它们必须服从相同的元素顺序。