C++11 和 C++17 基于范围的 For 循环是否可以迭代到特定位置而不是地图的整个范围?
Can C++11 and C++17 Range-Based For Loop iterate to a specific position instead of full range of the map?
是否有C++11和C++17版本的基于范围的For循环迭代器可以迭代到地图中的某个位置?
例如,如果一个映射有 10 个键值元素,那么我如何才能只遍历前三个键值元素?
以下代码仅遍历地图的整个范围。
//C++11
for(auto m: mapData){
cout << m.first << ": " << m.second << endl;
}
//C++17
for(auto [key, val]: mapData){
cout << key << ": " << val << endl;
}
您要么需要一个外部计数器来提前退出,例如:
int n = 0;
for(auto [k, v] : map)
{
if(++n > 10) break;
std::cout << k << ": " << v << std::endl;
}
或者,如果你不怕复制地图,你可以这样做:
std::map<...> copy { map.begin(), std::next(map.begin(), 10) };
for(auto [k, v] : copy) std::cout << k << ": " << v << std::endl;
最后,如果您可以使用C++20,那么您可以简单地这样做:
#include <ranges>
for(auto [k, v] : map | std::views::take(10))
{
std::cout << k << ": " << v << std::endl;
}
Range-based for 循环只是 syntactic-sugar 超过正常的 begin()
和 end()
调用。由于 std::map
没有 random-access 迭代器这一事实使您的部分迭代请求变得复杂 - 这会导致每个迭代器递增的成本。
为了避免多余的成本,您最好的选择是我们 range-based for 循环到一个特定的计数器 break
:
auto count = 0;
for (const auto& [k,v] : map) {
if (++count > n) { break; }
// process 'k', 'v'
}
如果您正在寻找“标准”方法,可以使用 std::for_each_n
来选择长度。您只需要确保计数不超过容器的长度:
auto length = std::min(map.size(), n);
std::for_each_n(map.begin(), n, [&](const auto& kv) {
// process kv
});
尽管 std::for_each_n
方法在很大程度上等同于使用计数器的第一种方法。
如果扩展支持c++20, your options open up a bit since you can construct a std::ranges::subrange
:
for (const auto& [k,v] : std::ranges::subrange(map.begin(), std::advance(map.end(), n)) {
// process 'k', 'v'
}
这种方法的缺点是 std::map
迭代器不是 random-access —— 这意味着您要付出迭代序列 两次 的代价。在大多数情况下,仅仅尝试利用 range-based for
循环并不值得。
编辑: 请参阅@InnocentBystander 的回答 std::views::take(...)
作为替代方案,这将有效地产生等同于 count
+break
的内容基于方法。
是否有C++11和C++17版本的基于范围的For循环迭代器可以迭代到地图中的某个位置? 例如,如果一个映射有 10 个键值元素,那么我如何才能只遍历前三个键值元素? 以下代码仅遍历地图的整个范围。
//C++11
for(auto m: mapData){
cout << m.first << ": " << m.second << endl;
}
//C++17
for(auto [key, val]: mapData){
cout << key << ": " << val << endl;
}
您要么需要一个外部计数器来提前退出,例如:
int n = 0;
for(auto [k, v] : map)
{
if(++n > 10) break;
std::cout << k << ": " << v << std::endl;
}
或者,如果你不怕复制地图,你可以这样做:
std::map<...> copy { map.begin(), std::next(map.begin(), 10) };
for(auto [k, v] : copy) std::cout << k << ": " << v << std::endl;
最后,如果您可以使用C++20,那么您可以简单地这样做:
#include <ranges>
for(auto [k, v] : map | std::views::take(10))
{
std::cout << k << ": " << v << std::endl;
}
Range-based for 循环只是 syntactic-sugar 超过正常的 begin()
和 end()
调用。由于 std::map
没有 random-access 迭代器这一事实使您的部分迭代请求变得复杂 - 这会导致每个迭代器递增的成本。
为了避免多余的成本,您最好的选择是我们 range-based for 循环到一个特定的计数器 break
:
auto count = 0;
for (const auto& [k,v] : map) {
if (++count > n) { break; }
// process 'k', 'v'
}
如果您正在寻找“标准”方法,可以使用 std::for_each_n
来选择长度。您只需要确保计数不超过容器的长度:
auto length = std::min(map.size(), n);
std::for_each_n(map.begin(), n, [&](const auto& kv) {
// process kv
});
尽管 std::for_each_n
方法在很大程度上等同于使用计数器的第一种方法。
如果扩展支持c++20, your options open up a bit since you can construct a std::ranges::subrange
:
for (const auto& [k,v] : std::ranges::subrange(map.begin(), std::advance(map.end(), n)) {
// process 'k', 'v'
}
这种方法的缺点是 std::map
迭代器不是 random-access —— 这意味着您要付出迭代序列 两次 的代价。在大多数情况下,仅仅尝试利用 range-based for
循环并不值得。
编辑: 请参阅@InnocentBystander 的回答 std::views::take(...)
作为替代方案,这将有效地产生等同于 count
+break
的内容基于方法。