web-dev-qa-db-ja.com

終わりから始まりへのC ++ベクトルの反復

ベクトルを最後から最初まで繰り返すことは可能ですか?

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

または、それはそのようなものでのみ可能です:

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

最善の方法は次のとおりです。

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

rbegin()/rend()は、特にその目的のために設計されました。 (そして、はい、_reverse_interator_をインクリメントすると後方に移動します。)

理論的には、メソッドは(begin()/end()&_--i_を使用して)動作します。_std::vector_の反復子は双方向ですが、end()は最後の要素ではありません—最後の要素を超えているため、最初にデクリメントする必要があり、begin()に達したら完了です。しかし、処理を行う必要があります。

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

} 
_

更新:for()ループをwhile()ループに書き直すことに、私は明らかに積極的すぎました。 (重要な部分は_--i_が先頭にあることです。)

122
James Curran

C++ 11を使用している場合は、autoを使用できます。

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

クローズド・オープン範囲を逆反復するための確立された「パターン」は次のようになります

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

または、必要に応じて、

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

このパターンは、たとえば、符号なしインデックスを使用して配列の逆インデックスを作成する場合に使用できます

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

(このパターンに馴染みのない人は、配列のインデックス付けにsigned integer型を使用することをしばしば主張します。これは、符号なしの型は逆インデックス付けを防止すると誤って信じているためです)

「スライディングポインター」手法を使用して配列を反復処理するために使用できます。

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

または、通常の(逆ではない)反復子を使用して、ベクトルの逆反復に使用できます

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

ユーザーrend() / rbegin()イテレーター:

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

9
a1ex07
_template<class It>
std::reverse_iterator<It> reversed( It it ) {
  return std::reverse_iterator<It>(std::forward<It>(it));
}
_

次に:

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

または、C++ 14では次のようにします。

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

C++ 03/11では、ほとんどの標準コンテナには.rbegin()および.rend()メソッドもあります。

最後に、次のように範囲アダプター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) ) };
}
_

そして今、あなたはこれを行うことができます:

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

かなりきれいだと思います。

逆イテレータを使用し、rbegin()からrend()にループします

4
Steve Townsend

私は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();}
};

私はこのような通常のイテレータを取ることができます:

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

そして、これを逆に反復するように変更します:

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

これは、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));
}

これは、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))
    ;
0
Mordachai