对于 std::set 中给定的下限和上限,如何在地图中获取一系列值?
How Can I get a range of values in a map for given lower bound and upper bound in an std::set?
假设我有以下代码
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
int inf, sup;
inf = 25; sup = 60;
for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90
return 0;
}
我试图弄清楚标准库是否提供了任何方法或方法组合,可以让我获得两个迭代器 it_l, it_u
,从而覆盖 [inf,sup] 范围。我曾尝试使用 lower_bound、upper_bound,但我误解了它们的工作原理。这个想法是避免编写循环(因为我知道我可以为此任务编写自己的函数,但也许有一些我不知道的替代方法)。
更新:预期输出的一些例子是(在我的例子中)
inf =25; sup = 60
我预计 {30,40,50,60}
如果改为
inf=30; sup = 60
我预计 {30,40,50,60}
如果
inf=25; sup = 65
我预计 {30,40,50,60}
显然有误会,或者是我没有正确表达我想做的事情。
当我说 inf 和 sup 时,请将它们理解为实数区间的极值。做出这样的假设后,我想要检索的是区间 [inf,sup] 与集合对象指定的离散集合之间的交集。我刚才说的和我举的例子有矛盾吗?
让A={10 20 30 40 50 60 70 80 90}
、B1=[25,60]
、B2=[30,60]
和B3=[25,65]
对于每个 i=1,2,3
A
和 Bi
之间的交集给出了我在示例中所说的内容。
看来你只是想要这个:
auto it_l = myset.lower_bound(inf);
auto it_u = myset.lower_bound(sup + 1);
这样,您将得到半开区间 [it_l, it_u)
,其中所有元素 i
来自 myset
并且是 inf <= i <= sup
(即恰好你想要什么)。半开迭代器区间是整个标准库都使用的,所以你应该没问题。
C++ 使用半开范围。也就是说,[inf, sup)
,永远不会[inf, sup]
。标准库很好地支持半开范围惯用语:只需使用 std::set::lower_bound
和 std::set::upper_bound
。 (不是 std::upper bound
等)。封闭式的不行,非要用就得靠自己了。我建议采用标准方式并在任何地方切换到半开范围。
这对我来说很好用:
#include <iostream>
#include <set>
template <typename T>
std::pair<typename std::set<T>::const_iterator, typename std::set<T>::const_iterator>
infsup(const std::set<T>& set, const T& inf, const T& sup)
{
return std::make_pair(set.lower_bound(inf), set.upper_bound(sup));
}
int main ()
{
std::set<int> myset;
int inf, sup;
for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90
for (auto its = infsup(myset, 30, 60); its.first != its.second; ++its.first)
{
std::cout << " " << *its.first; // 30 40 50 60
}
std::cout << std::endl;
for (auto its = infsup(myset, 25, 65); its.first != its.second; ++its.first)
{
std::cout << " " << *its.first; // 30 40 50 60
}
std::cout << std::endl;
return 0;
}
Using lower_bound
for inf
表示起始迭代器将指向第一个不小于inf
的元素,并且所以满足你想要的范围下限的条件。
对sup
使用upper_bound
意味着结束迭代器将指向_第一个大于sup
_的元素。请注意,在 C++ 中,结束迭代器始终指向 刚好超过范围的结束 ,因此 sup
将被包括在内。
编辑以反映评论中的讨论(感谢@Useless 指出):请注意,这适用于空结果范围,例如
- 当
inf
和sup
都小于集合中的最小元素时
- 当两者都大于最大元素时
- 当 [inf, sup] 中没有元素时(在您的示例中,假设
inf=25, sup=29
)
但是如果您选择 inf > sup
以便返回的迭代器引用不同的元素,那么 its.first > its.second
会使 for
循环(正如我在上面写的)失败。因此,由您来确保 inf <= sup
(就像您可能正在编写的任何其他 for
循环一样)。
不清楚为什么说上限和下限不是你想要的。
lower_bound 将 return 一个迭代器,指向您要查找的第一个元素(第一个不小于参数的元素)
upper_bound 为您提供大于参数的第一个元素(在您的示例中为 70),但这就是 stl 迭代器的工作方式,端点指向最后一个元素之外的一个元素。
如果你真的想要一个副本,这 2 个迭代器可用于制作元素的副本 - 但你也可以只使用它们来访问原始集合的元素 - 该范围将包括 60 但不包括 70在你的例子中。
假设我有以下代码
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
int inf, sup;
inf = 25; sup = 60;
for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90
return 0;
}
我试图弄清楚标准库是否提供了任何方法或方法组合,可以让我获得两个迭代器 it_l, it_u
,从而覆盖 [inf,sup] 范围。我曾尝试使用 lower_bound、upper_bound,但我误解了它们的工作原理。这个想法是避免编写循环(因为我知道我可以为此任务编写自己的函数,但也许有一些我不知道的替代方法)。
更新:预期输出的一些例子是(在我的例子中)
inf =25; sup = 60
我预计 {30,40,50,60}
如果改为
inf=30; sup = 60
我预计 {30,40,50,60}
如果
inf=25; sup = 65
我预计 {30,40,50,60}
显然有误会,或者是我没有正确表达我想做的事情。
当我说 inf 和 sup 时,请将它们理解为实数区间的极值。做出这样的假设后,我想要检索的是区间 [inf,sup] 与集合对象指定的离散集合之间的交集。我刚才说的和我举的例子有矛盾吗?
让A={10 20 30 40 50 60 70 80 90}
、B1=[25,60]
、B2=[30,60]
和B3=[25,65]
对于每个 i=1,2,3
A
和 Bi
之间的交集给出了我在示例中所说的内容。
看来你只是想要这个:
auto it_l = myset.lower_bound(inf);
auto it_u = myset.lower_bound(sup + 1);
这样,您将得到半开区间 [it_l, it_u)
,其中所有元素 i
来自 myset
并且是 inf <= i <= sup
(即恰好你想要什么)。半开迭代器区间是整个标准库都使用的,所以你应该没问题。
C++ 使用半开范围。也就是说,[inf, sup)
,永远不会[inf, sup]
。标准库很好地支持半开范围惯用语:只需使用 std::set::lower_bound
和 std::set::upper_bound
。 (不是 std::upper bound
等)。封闭式的不行,非要用就得靠自己了。我建议采用标准方式并在任何地方切换到半开范围。
这对我来说很好用:
#include <iostream>
#include <set>
template <typename T>
std::pair<typename std::set<T>::const_iterator, typename std::set<T>::const_iterator>
infsup(const std::set<T>& set, const T& inf, const T& sup)
{
return std::make_pair(set.lower_bound(inf), set.upper_bound(sup));
}
int main ()
{
std::set<int> myset;
int inf, sup;
for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90
for (auto its = infsup(myset, 30, 60); its.first != its.second; ++its.first)
{
std::cout << " " << *its.first; // 30 40 50 60
}
std::cout << std::endl;
for (auto its = infsup(myset, 25, 65); its.first != its.second; ++its.first)
{
std::cout << " " << *its.first; // 30 40 50 60
}
std::cout << std::endl;
return 0;
}
Using lower_bound
for inf
表示起始迭代器将指向第一个不小于inf
的元素,并且所以满足你想要的范围下限的条件。
对sup
使用upper_bound
意味着结束迭代器将指向_第一个大于sup
_的元素。请注意,在 C++ 中,结束迭代器始终指向 刚好超过范围的结束 ,因此 sup
将被包括在内。
编辑以反映评论中的讨论(感谢@Useless 指出):请注意,这适用于空结果范围,例如
- 当
inf
和sup
都小于集合中的最小元素时 - 当两者都大于最大元素时
- 当 [inf, sup] 中没有元素时(在您的示例中,假设
inf=25, sup=29
)
但是如果您选择 inf > sup
以便返回的迭代器引用不同的元素,那么 its.first > its.second
会使 for
循环(正如我在上面写的)失败。因此,由您来确保 inf <= sup
(就像您可能正在编写的任何其他 for
循环一样)。
不清楚为什么说上限和下限不是你想要的。
lower_bound 将 return 一个迭代器,指向您要查找的第一个元素(第一个不小于参数的元素)
upper_bound 为您提供大于参数的第一个元素(在您的示例中为 70),但这就是 stl 迭代器的工作方式,端点指向最后一个元素之外的一个元素。
如果你真的想要一个副本,这 2 个迭代器可用于制作元素的副本 - 但你也可以只使用它们来访问原始集合的元素 - 该范围将包括 60 但不包括 70在你的例子中。