2013-01-08 22 views
13

私はC++の新機能です。構造体のベクトルを特定のメンバーデータで検索する方法を見つけようとしています。ベクトル内の構造体アイテムをメンバーデータで検索する

私は、これはベクトルでシンプルなタイプ

std::find(vector.begin(), vector.end(), item) != vector.end() 

に働くだろう知っている。しかし、私はこのような構造体を持って言うことができます:

struct Friend 
{ 
    string name; 
    string number; 
    string ID; 
}; 

と、このようなベクトル:

vector<Friend> friends; 

その後、ベクトルは友達で満たされます。

私は特定のIDを持つ友人を検索し、詳細を説明したいとしましょう。または、特定の構造体をベクターから削除します。これを行う簡単な方法はありますか?

答えて

19

これはstd::find_ifと利用できるあなたがC++ 11(またはC++ 0xの)を持っている場合はラムダ関数として表すことができ、検索述語、で行うことができます。

auto pred = [](const Friend & item) { 
    return item.ID == 42; 
}; 
std::find_if(std::begin(friends), std::end(friends), pred) != std::end(friends); 

IDを使用するにはあなたが利用できるC++ 11を持っていない場合、あなたはファンクタとして述語を定義する必要があり

auto pred = [id](const Friend & item) { 
    return item.ID == id; 
}; 
std::find_if(std::begin(friends), std::end(friends), pred) != std::end(friends); 

:それは([...]内)ラムダ式にキャプチャに変数として、あなたが持っている与えられました(関数オブジェクト)。 Remy Lebeau's answerはこのアプローチを使用します。

述語で定義されている条件に一致する要素を削除するには、find_ifの代わりにremove_ifを使用します(残りの構文は同じです)。

アルゴリズムの詳細については、the STL <algorithm> referenceを参照してください。

+0

を使用! – DanDan

+0

@ダンダンええ、ラムダを関数の引数として使用する場所を直接定義したくない場合があります(それで、その行が長くなりすぎます) – leemes

+0

なぜ最初に '.begin()'を使い、 std :: begin'? –

4

またはラムダ(あなたがC++ 98で作業している場合)(あなたは私が仮定しますC++ 11を、使用している場合)あなたはファンクタとの組み合わせでstd::find_ifを使用することができます。

using namespace std; 
int ID = 3; // Let's say... 
auto it = find_if(begin(vector), end(vector), [=] (Friend const& f) { 
    return (f.ID == ID); 
    }); 
bool found = (it != end(vector)); 
12

使用std::find_if() 。 @leemesと@AndyProwlはC++ 11コンパイラでの使用方法を示しました。

class MatchesID 
{ 
    std::string _ID; 

public: 
    MatchesID(const std::string &ID) : _ID(ID) {} 

    bool operator()(const Friend &item) const 
    { 
     return item.ID == _ID; 
    } 
}; 

std::find_if(vector.begin(), vector.end(), MatchesID("TheIDHere")) != vector.end(); 

場合:C++ 11コンパイラを使用していない場合でも、あなたは、この代わりに、そのコンストラクタで以前に指定されたIDで指定したアイテムのIDを比較ファンクタを定義するようにそれを使用することができますあなたはIDを使用するプロジェクト内の他のクラスを持って、あなたはこのファンクタをテンプレート化することができます:

template<typename IDType> 
class MatchesID 
{ 
    IDType _ID; 

public: 
    MatchesID(const IDType &ID) : _ID(ID) {} 

    template<class ItemType> 
    bool operator()(const ItemType &item) const 
    { 
     return item.ID == _ID; 
    } 
}; 

std::find_if(vector.begin(), vector.end(), MatchesID<std::string>("TheIDHere")) != vector.end(); 
+0

私はあなたのファンクターを一般的にしました、それで、それは他のタイプで使用することができます。 – leemes

+0

@leemes:もしあなたがこのアプローチに従えば、私はIDのデータ型にもテンプレートを使うことを提案します。 –

2

あなたはSTLコンテナ内の要素を検索したい場合は、C++ 03ではstd::findまたはstd::find_ifアルゴリズム を使用するには、次のものが必要オーバーロード演算子== std :: findの場合

bool operator==(const Friend& lhs, const Friend& rhs) 
{ 
    return lhs.ID == rhs.ID; 
} 

if (std::find(friends.begin(), friends.end(), item) != friends.end()) 
{ 
    // find your friend 
} 

またはラムダでC++ 11:

std::find_if(friends.begin(), friends.end(), [](Friend& f){ return f.ID == "1"; }); 

あなたが特定の要素を削除したい場合は、それは自動車の素敵な使い方だstd::remove_if

std::remove_if(friends.begin(), friends.end(), 
     [](Friend& f){ return f.ID == "1"; }); 
+0

この方法では、ロジックをローカルにしないでください。他のシナリオでは、「Friend」インスタンスの等価性の定義が異なる場合があります。ちょうど言って...(IDはユニークでなければならないので、これは問題ありません) – leemes

+0

これはC++ 11の美しさです – billz

関連する問題