web-dev-qa-db-ja.com

std :: mapのループの最後の反復を検出するにはどうすればよいですか?

次のようなことを行うために、マップ上のループの最後の反復にいるかどうかを判断するための最良の方法を見つけようとしています。

for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
    bool last_iteration;
    // do something for all iterations
    if (!last_iteration) {
        // do something for all but the last iteration
    }
}

これを行うにはいくつかの方法があるようです:ランダムアクセスイテレータ、distance関数など。正規の方法は何ですか?

編集:マップのランダムアクセスイテレータはありません!

27
cdleary

カノニカル?私はそれを主張することはできませんが、私は提案します

final_iter = someMap.end();
--final_iter;
if (iter != final_iter) ...

編集[〜#〜] ktc [〜#〜](ありがとう!時々あなたはあまりにも速く行き、最も単純なことを台無しにします...)

25
Mark Ransom

C++ 11以降、std :: next()も使用できます。

   for (auto iter = someMap.begin(); iter != someMap.end(); ++iter) { 
        // do something for all iterations
        if (std::next(iter) != someMap.end()) {
            // do something for all but the last iteration
        }
    }

少し前に質問されましたが、共有する価値があると思いました。

18
dutchdukes

これは最も単純なようです:

bool last_iteration = iter == (--someMap.end());
14
Torlack

ForwardIteratorを使用したいだけの場合、これは機能するはずです。

for ( i = c.begin(); i != c.end(); ) {
        iterator cur = i++;
        // do something, using cur
        if ( i != c.end() ) {
                // do something using cur for all but the last iteration
        }
}
10
camh

Mark Ransomを変更して、実際に意図したとおりに機能するようにしました。

finalIter = someMap.end();
--finalIter;
if (iter != final_iter)
6
KTC

まだ誰もそれについて言及していないことに驚いたが、もちろんブーストには何かがある;)

Boost.Next (および同等のBoost.Prior)

あなたの例は次のようになります:

for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
    // do something for all iterations
    if (boost::next(iter) != someMap.end()) {
        // do something for all but the last iteration
    }
}
6
Pieter

次のコードはコンパイラーによって最適化されるため、パフォーマンスとOOPルール)によってこのタスクに最適なソリューションになります。

if (&*it == &*someMap.rbegin()) {
    //the last iteration
}

Std :: mapには次のようなコード用の特別なメンバー関数rbeginがあるため、これはOOPルールによる最良のコードです。

final_iter = someMap.end();
--final_iter;
3
mpoleg

EOFを見つけて、何かを与えないようにする理由。

単に、それを除外します;

for (iter = someMap.begin(); someMap.end() - 1; ++iter) {
    //apply to all from begin to second last element
}

KISS(KEEP IT SIMPLY SIMPLE)

1
Angelin Nadar
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <algorithm>

using namespace boost::lambda;

// call the function foo on each element but the last...
if( !someMap.empty() )
{
  std::for_each( someMap.begin(), --someMap.end(), bind( &Foo, _1 ) );
}

Std :: for_eachを使用すると、ループがタイトで正確になります...単一の引数を取る関数foo()の導入に注意してください(型はsomeMapに含まれているものと一致する必要があります)。このアプローチには、1行であるという追加の追加があります。もちろん、Fooが本当に小さい場合は、ラムダ関数を使用して&Fooの呼び出しを取り除くことができます。

1
paxos1977

シンプルでありながら効果的なアプローチ:

  size_t items_remaining = someMap.size();

  for (iter = someMap.begin(); iter != someMap.end(); iter++) {
    bool last_iteration = items_remaining-- == 1;
  }
0
Jason Etheridge

これが私の最適化されたテイクです:

iter = someMap.begin();

do {
    // Note that curr = iter++ may involve up to three copy operations
    curr = iter;

    // Do stuff with curr

    if (++iter == someMap.end()) {
        // Oh, this was the last iteration
        break;
    }

    // Do more stuff with curr

} while (true);
0
Ates Goral

これはどうですか、誰も言及していませんが...

for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
    // do something for all iterations
    if (iter != --someMap.end()) {
        // do something for all but the last iteration
    }
}

これは単純なようです、mm.。

0
Todoroki