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
関数など。標準的な方法は何ですか?
編集:マップのランダムアクセスイテレータはありません!
解決
標準ですか?それを主張することはできませんが、提案します
final_iter = someMap.end();
--final_iter;
if (iter != final_iter) ...
編集 KTC 。(ありがとう!あまりにも早く行き過ぎて、最も単純なことを台無しにしてしまうこともある...)
他のヒント
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
}
}
しばらく前に質問がされましたが、共有する価値があると思いました。
これは最も簡単なようです:
bool last_iteration = iter == (--someMap.end());
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
}
}
実際に意図したとおりに動作するようにMark Ransomを変更しました。
finalIter = someMap.end();
--finalIter;
if (iter != final_iter)
驚いた人はまだ誰も言及していませんが、もちろんブーストには何かあります;)
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
}
}
次のコードは、パフォーマンスとOOPルールによってこのタスクに最適なソリューションになるように、コンパイラによって最適化されます。
if (&*it == &*someMap.rbegin()) {
//the last iteration
}
std :: mapには次のようなコード用の特別なメンバー関数rbeginがあるため、これはOOPルールによる最適なコードです。
final_iter = someMap.end();
--final_iter;
#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が非常に小さい場合は、ラムダ関数を使用して&amp; Fooへの呼び出しを削除できます。
EOFを見つけて何かを与えないようにするにはどうすればよいですか。
単に除外します。
for (iter = someMap.begin(); someMap.end() - 1; ++iter) {
//apply to all from begin to second last element
}
KISS(シンプルに保つ)
シンプルでありながら効果的なアプローチ:
size_t items_remaining = someMap.size();
for (iter = someMap.begin(); iter != someMap.end(); iter++) {
bool last_iteration = items_remaining-- == 1;
}
最適化されたテイクは次のとおりです:
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);
これについては、誰も言及していませんが...
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 ...
フルプログラム:
#include <iostream>
#include <list>
void process(int ii)
{
std::cout << " " << ii;
}
int main(void)
{
std::list<int> ll;
ll.push_back(1);
ll.push_back(2);
ll.push_back(3);
ll.push_back(4);
ll.push_back(5);
ll.push_back(6);
std::list<int>::iterator iter = ll.begin();
if (iter != ll.end())
{
std::list<int>::iterator lastIter = iter;
++ iter;
while (iter != ll.end())
{
process(*lastIter);
lastIter = iter;
++ iter;
}
// todo: think if you need to process *lastIter
std::cout << " | last:";
process(*lastIter);
}
std::cout << std::endl;
return 0;
}
このプログラムの結果:
1 2 3 4 5 | last: 6
繰り返しの前にマップから要素を引き出して、「最後の繰り返し」を実行するだけです。ループを抜けてから、要素をマップに戻します 。これは非同期コードにとってはひどく悪いことですが、C ++の残りの部分が並行性にとってどれほど悪いかを考えると、それが問題になるとは思いません。 :-)