从结尾到开头迭代 C++ 向量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3610933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:16:19  来源:igfitidea点击:

Iterating C++ vector from the end to the begin

c++vectoriterator

提问by user

Is it possible to iterate a vector from the end to the begin?

是否可以从结尾到开头迭代一个向量?

for (vector<my_class>::iterator i = my_vector.end();
        i != my_vector.begin(); /* ?! */ ) {
}

Or is that only possible with something like that:

或者只有这样的事情才有可能:

for (int i = my_vector.size() - 1; i >= 0; --i) {
}

回答by James Curran

The best way is:

最好的办法是:

for (vector<my_class>::reverse_iterator i = my_vector.rbegin(); 
        i != my_vector.rend(); ++i ) { 
} 

rbegin()/rend()were especially designed for that purpose. (And yes, incrementing a reverse_interatormoves it backward.)

rbegin()/rend()是专门为此目的而设计的。(是的,增加 areverse_interator会将其向后移动。)

Now, in theory, your method (using begin()/end()& --i) would work, std::vector's iterator being bidirectional, but remember, end()isn't the last element — it's one beyond the last element, so you'd have to decrement first, and you are done when you reach begin()— but you still have to do your processing.

现在,理论上,您的方法(使用begin()/ end()& --i)可以工作,std::vector迭代器是双向的,但请记住,end()不是最后一个元素 - 它是最后一个元素之后的一个,因此您必须先递减,并且您是到达时完成begin()- 但您仍然需要进行处理。

vector<my_class>::iterator i = my_vector.end();
while (i != my_vector.begin())
{
     --i;
    /*do stuff */

} 

UPDATE: I was apparently too aggressive in re-writing the for()loop into a while()loop. (The important part is that the --iis at the beginning.)

更新:我显然在将for()循环重写为循环方面过于激进while()。(重要的部分是--i在开头。)

回答by Akavall

If you have C++11 you can make use of auto.

如果你有 C++11,你可以使用auto.

for (auto it = my_vector.rbegin(); it != my_vector.rend(); ++it)
{
}

回答by AnT

The well-established "pattern" for reverse-iterating through closed-open ranges looks as follows

通过闭开区间反向迭代的成熟“模式”如下所示

// Iterate over [begin, end) range in reverse
for (iterator = end; iterator-- != begin; ) {
  // Process `*iterator`
}

or, if you prefer,

或者,如果您愿意,

// Iterate over [begin, end) range in reverse
for (iterator = end; iterator != begin; ) {
  --iterator;
  // Process `*iterator`
}

This pattern is useful, for example, for reverse-indexing an array using an unsigned index

此模式很有用,例如,用于使用无符号索引反向索引数组

int array[N];
...
// Iterate over [0, N) range in reverse
for (unsigned i = N; i-- != 0; ) {
  array[i]; // <- process it
}

(People unfamiliar with this pattern often insist on using signedinteger types for array indexing specifically because they incorrectly believe that unsigned types are somehow "unusable" for reverse indexing)

(不熟悉这种模式的人经常坚持使用有符号整数类型进行数组索引,特别是因为他们错误地认为无符号类型在某种程度上“无法用于”反向索引)

It can be used for iterating over an array using a "sliding pointer" technique

它可用于使用“滑动指针”技术迭代数组

// Iterate over [array, array + N) range in reverse
for (int *p = array + N; p-- != array; ) {
  *p; // <- process it
}

or it can be used for reverse-iteration over a vector using an ordinary (not reverse) iterator

或者它可以用于使用普通(非反向)迭代器对向量进行反向迭代

for (vector<my_class>::iterator i = my_vector.end(); i-- != my_vector.begin(); ) {
  *i; // <- process it
}

回答by a1ex07

User rend() / rbegin()iterators:

用户rend() / rbegin()迭代器:

for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)

for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)

回答by Yakk - Adam Nevraumont

template<class It>
std::reverse_iterator<It> reversed( It it ) {
  return std::reverse_iterator<It>(std::forward<It>(it));
}

Then:

然后:

for( auto rit = reversed(data.end()); rit != reversed(data.begin()); ++rit ) {
  std::cout << *rit;

Alternatively in C++14 just do:

或者,在 C++14 中只需执行以下操作:

for( auto rit = std::rbegin(data); rit != std::rend(data); ++rit ) {
  std::cout << *rit;

In C++03/11 most standard containers have a .rbegin()and .rend()method as well.

在 C++03/11 中,大多数标准容器也有.rbegin()and.rend()方法。

Finally, you can write the range adapter backwardsas follows:

最后,您可以backwards按如下方式编写范围适配器:

namespace adl_aux {
  using std::begin; using std::end;
  template<class C>
  decltype( begin( std::declval<C>() ) ) adl_begin( C&& c ) {
    return begin(std::forward<C>(c));
  }
  template<class C>
  decltype( end( std::declval<C>() ) ) adl_end( C&& c ) {
    return end(std::forward<C>(c));
  }
}

template<class It>
struct simple_range {
  It b_, e_;
  simple_range():b_(),e_(){}
  It begin() const { return b_; }
  It end() const { return e_; }
  simple_range( It b, It e ):b_(b), e_(e) {}

  template<class OtherRange>
  simple_range( OtherRange&& o ):
    simple_range(adl_aux::adl_begin(o), adl_aux::adl_end(o))
  {}

  // explicit defaults:
  simple_range( simple_range const& o ) = default;
  simple_range( simple_range && o ) = default;
  simple_range& operator=( simple_range const& o ) = default;
  simple_range& operator=( simple_range && o ) = default;
};
template<class C>
simple_range< decltype( reversed( adl_aux::adl_begin( std::declval<C&>() ) ) ) >
backwards( C&& c ) {
  return { reversed( adl_aux::adl_end(c) ), reversed( adl_aux::adl_begin(c) ) };
}

and now you can do this:

现在你可以这样做:

for (auto&& x : backwards(ctnr))
  std::cout << x;

which I think is quite pretty.

我认为这很漂亮。

回答by Steve Townsend

Use reverse iterators and loop from rbegin()to rend()

使用反向迭代器并从rbegin()到循环rend()

回答by florestan

Starting with c++20, you can use a std::ranges::reverse_viewand a range-based for-loop:

从 c++20 开始,您可以使用 astd::ranges::reverse_view和基于范围的 for 循环:

#include<ranges>
#include<vector>
#include<iostream>

using namespace std::ranges;

std::vector<int> const vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

for(auto& i :  views::reverse(vec)) {
    std::cout << i << ",";
}

Or even

甚至

for(auto& i :  vec | views::reverse)

Unfortunately, at the time of writing (Jan 2020) no major compiler implements the ranges library, but you can resort to Eric Niebler's ranges-v3:

不幸的是,在撰写本文时(2020 年 1 月),还没有主要编译器实现 range 库,但您可以求助于Eric Niebler 的 Ranges-v3

#include <iostream>
#include <vector>
#include "range/v3/all.hpp"

int main() {

    using namespace ranges;

    std::vector<int> const vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for(auto& i :  views::reverse(vec)) {
        std::cout << i << ",";
    }

    return 0;
}

回答by Mordachai

Here's a super simple implementation that allows use of the for each construct and relies only on C++14 std library:

这是一个超级简单的实现,它允许使用 for each 构造并且仅依赖于 C++14 std 库:

namespace Details {

    // simple storage of a begin and end iterator
    template<class T>
    struct iterator_range
    {
        T beginning, ending;
        iterator_range(T beginning, T ending) : beginning(beginning), ending(ending) {}

        T begin() const { return beginning; }
        T end() const { return ending; }
    };

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usage:
//  for (auto e : backwards(collection))
template<class T>
auto backwards(T & collection)
{
    using namespace std;
    return Details::iterator_range(rbegin(collection), rend(collection));
}

This works with things that supply an rbegin() and rend(), as well as with static arrays.

这适用于提供 rbegin() 和 Rend() 以及静态数组的事物。

std::vector<int> collection{ 5, 9, 15, 22 };
for (auto e : backwards(collection))
    ;

long values[] = { 3, 6, 9, 12 };
for (auto e : backwards(values))
    ;

回答by John Stephen

I like the backwards iterator at the end of Yakk - Adam Nevraumont's answer, but it seemed complicated for what I needed, so I wrote this:

我喜欢 Yakk 末尾的向后迭代器 - Adam Nevraumont 的回答,但对于我需要的东西来说似乎很复杂,所以我写了这个:

template <class T>
class backwards {
    T& _obj;
public:
    backwards(T &obj) : _obj(obj) {}
    auto begin() {return _obj.rbegin();}
    auto end() {return _obj.rend();}
};

I'm able to take a normal iterator like this:

我可以像这样使用普通的迭代器:

for (auto &elem : vec) {
    // ... my useful code
}

and change it to this to iterate in reverse:

并将其更改为此以反向迭代:

for (auto &elem : backwards(vec)) {
    // ... my useful code
}

回答by amit kumar

use this code

使用此代码

//print the vector element in reverse order by normal iterator.
cout <<"print the vector element in reverse order by normal iterator." <<endl;
vector<string>::iterator iter=vec.end();
--iter;
while (iter != vec.begin())
{
    cout << *iter  << " "; 
    --iter;
}