【问题标题】:C++ iterate container backwards N stepsC++ 向后迭代容器 N 步
【发布时间】:2019-10-21 19:45:58
【问题描述】:

在 C++ 中,我可以使用 reverse_iterator 向后循环容器的元素,例如 list

如何迭代一定数量的元素?还没到起点?此代码有效,但我觉得有更好的方法。

std::list<int> mylist{1,2,3,4,5};
int cnt = 3;
for (auto rit = mylist.rbegin(); rit != mylist.rend(); ++rit) {
    if (cnt == 0) break;
    std::cout << *rit << " ";
    --cnt;
}

预期输出{5, 4, 3}

【问题讨论】:

  • 至少,您的解决方案是稳健的。如果容器中的元素少于 3 个,它甚至不会失败。如果您使用 mylist.rbegin() + 3 作为结束条件,则不会出现这种情况...
  • 我可以添加范围检查
  • 您已有的解决方案也适用于所有迭代器类型。

标签: c++ list reverse-iterator


【解决方案1】:

您可以按如下方式调整循环:

for (auto rit = mylist.rbegin(); rit != std::next(mylist.rbegin(), 3); ++rit)
{
   std::cout << *rit << " ";
}

但请注意,要使其可靠工作,您需要检查列表是否至少为 3 大小或将参数调整为 std::next,如 const auto n = std::min&lt;std::size_t&gt;(3, mylist.size());

使用 C++20,你应该可以使用(显然没有测试)

#include <ranges>

for (int n : mylist | std::ranges::reverse_view | std::ranges::take_view(3))
  std::cout << n << "\n";

这使得大小测试变得多余,因为take_view 受范围大小的限制(它在内部执行此检查)。

【讨论】:

    【解决方案2】:

    还没开始?

    如果你能保证,那么

    std::copy_n(mylist.rbegin(), 3, std::ostream_iterator<int>(std::cout, " "));
    

    或者更安全

    std::copy_n(mylist.rbegin(), std::min(mylist.size(), std::list<int>::size_type(3)), std::ostream_iterator<int>(std::cout, " "));
    

    LIVE

    【讨论】:

      【解决方案3】:

      我不会把递增/递减和检查条件放在循环体中,而是把它放在你最期待的地方:

      std::list<int> mylist{1,2,3,4,5};
      int cnt = 3;
      for (auto rit = mylist.rbegin(); rit != mylist.rend() && cnt > 0; ++rit,--cnt) {
          std::cout << *rit << " ";
      }
      

      例如,现在您可以在循环主体的任何位置添加continue,而不会造成循环破坏。

      PS:实际上我更喜欢其他答案,但我会留下这个答案,因为它是最小的变化,并且恕我直言,如果可能的话,应该避免在循环体内增加/检查循环计数器(并且可以在这里)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-01-17
        • 1970-01-01
        • 1970-01-01
        • 2013-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多