2010-11-22 9 views
8

私はJavaからC++に入ってきており、標準的なものから要素(非プリミティブ)を持っている標準的な設計状況を持っています。C++のstd :: vectorのArrayListスタイルのindexOf?

Javaの場合、次のように記述します。 arrayList.remove(arrayList.indexOf(myClassInstance));

、std :: vectorを使って、これを実行するには最高のパフォーマンス/最もクリーンな方法はありますか?

私が考えることができる最も良いことは、私が探しているインスタンスへの参照を作成し、その参照を見つけるまでベクトルを反復処理することです。本質的には、ベクトルの各要素のメモリアドレスを参照と比較して一致するまで比較します。

私は適切なトラックにいますか?またはこれを行うためのよりよい方法がありますか? (おそらく、別の標準コンテナを使用して、私は今までのところstd :: vectorのみを使用しています)

+0

を使用すると、ポインタまたはshared_ptrののコレクションを持っていると仮定するとは、STD ::セットはあなたのためにうまく機能することがありポインタアドレスを比較するだけです。探しているアイテムのアドレスが分かっていればmySetだけです。消去(ptr); – CashCow

+0

@CashCow - std :: vectorとstd:vectorのすべてのメンバーに対して、繰り返しのパフォーマンス上の違いがありますか?私のコードの他の場所では、私はセット内の各要素について、すべてのサイクルでメソッドを呼び出しています。 – ericsoco

答えて

8
#include <algorithm> 

std::vector<Foo>::iterator it = std::find(vec.begin(), vec.end(), foo_2b_found); 
if (it != vec.end()) vec.erase(it); 
+1

私はあなたがその 'std :: find'コールの終わりにいくつかのものを見逃していると思います。 –

+1

iterating中に消去するのは悪い考えではありませんか?私がvector.eraseを呼び出すと、イテレータで処理され、無効化されても問題はなくなるので、ここでは悪い考えはないと思います。 – ericsoco

+0

@Billy:それを発見してくれてありがとう:) @eric:私たちが実際に*手動で反復した場合、私たちは非常に注意する必要があります。イテレータの無効化は非常に興味深いトピックです。別のFAQのにおいがしますか? ;-) – fredoverflow

4

要素を見つけるにはstd::findを、要素を見つけるにはvector::eraseを使用してください。

std::findは基本的にベクトルを繰り返して要素を検索し、単純なベクトルではそれ以上の処理はできません(JavaのArrayListの場合も同じです)。別のコンテナを使用する必要があるかどうかは、要件によって異なります。その後、

+0

+1。述語と一致する複数の項目を削除する場合は、 'std :: remove_if'も使用するべきです。 –

+0

oo。誰もが標準的なコンテナでできることがたくさんあったことを認識していない... - http://www.cplusplus.com/reference/algorithm/ – ericsoco

+0

@eric:ジェネリックプログラミングの素晴らしい世界へようこそ! – fredoverflow

1

あなたはベクトルを通じて直線的に検索する場合は

seq.erase(std::find(seq.begin(), seq.end(), elt)); 

あなたは、述語を持ってして、述語に一致するすべての項目を削除する場合:

seq.erase(std::remove_if(seq.begin(), seq.end(), Pred), seq.end()); 

のなしこれらの方法は線形ルックアップを必要とするため、最も効果的な方法です。要素が早期に発見されたとしても、他の要素をすべて移動させなければならないため、消去は高価ですs。

std :: listを使用すると、後者に対処できます。検索は線形ですが、消去は一定の時間になります。

キールックアップを使用する連想コンテナに要素を格納することができる場合は、O(ログN)ルックアップと一定時間の削除がより効率的になります。

ハッシュマップは、一定時間のルックアップと削除に近いほど良いかもしれません。

オブジェクトのポインタで消去することをお勧めします。タイプTにstd :: setを使用できます。次に、mySet.erase(pt);を使用してください。ここで、ptはポインタです。もちろん、あなたのポインタの寿命を管理する必要がありますが、あなたのコレクションから消去するものがどれかを知っているという事実は、あなたがそれを他の場所にコピーしていることを示唆しています。

あなたがのstd ::セットを使用する場合があり、SharedPtrLess>は次のようにSharedPtrLessを定義

template< typename T > 
struct SharedPtrLess 
{ 
    bool operator()(boost::shared_ptr<T> left, boost::shared_ptr<T> right) const 
    { 
    return std::less<T>()(left.get(), right.get()); 
    } 
}; 
+0

将来のための素晴らしいヒント。私はベルトの下でstd :: vectorを取得することから始め、そこから移動します...ありがとう! – ericsoco

関連する問題