2013-01-08 8 views
13

Ich bin sehr neu in C++ und ich versuche, einen Weg zu finden, einen Vektor von Strukturen für eine Struktur mit bestimmten Mitgliedsdaten zu suchen.Suche nach einem Strukturelement in einem Vektor von Elementdaten

Ich weiß, das mit einfachen Typen in den Vektor

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

Aber läßt sagen, ich habe eine Struktur wie diese funktionieren würde:

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

und einen Vektor wie folgt aus:

vector<Friend> friends; 

Dann ist der Vektor mit Freunden gefüllt.

Angenommen, ich möchte nach einem Freund mit einer bestimmten ID suchen und die Details anzeigen. Oder löschen Sie die bestimmte Struktur aus dem Vektor. Gibt es einen einfachen Weg, dies zu tun?

Antwort

19

kann dies mit std::find_if und ein Such Prädikat erfolgen, die als Lambda-Funktion ausgedrückt werden können, wenn Sie C++ 11 (oder C++ 0x) zur Verfügung:

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

eine ID verwenden als Variable angegeben, müssen Sie Capture es in dem Lambda-Ausdruck (innerhalb der [...]):

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

Wenn Sie nicht C++ 11 zur Verfügung haben, müssen Sie das Prädikat als Funktors definieren (Funktionsobjekt). Remy Lebeau's answer verwendet diesen Ansatz.

Um Elemente zu entfernen, die den Kriterien des Prädikats entsprechen, verwenden Sie remove_if anstelle von find_if (der Rest der Syntax ist identisch).

Weitere Algorithmen finden Sie unter the STL <algorithm> reference.

+0

Es ist eine schöne Verwendung von Auto! – DanDan

+0

@DanDan Yeah, manchmal möchte ich das Lambda nicht direkt definieren, wo es als Argument für eine Funktion verwendet wird (es macht die Zeile so lang) – leemes

+0

Warum verwendet das erste '.begin()' und das zweite ' std :: beginnen? –

4

Sie std::find_if in Kombination mit functors verwenden können oder Lambda (wenn Sie mit C++ 98 arbeiten) (wenn Sie C++ 11 verwenden, die ich übernehmen werde):

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

Verwenden std::find_if() . @leemes und @AndyProwl haben gezeigt, wie man es in einem C++ 11-Compiler verwendet.Aber wenn Sie kein C++ 11-Compiler, dann können Sie es wie diese stattdessen verwenden, die eine Funktors die ID eines Artikels mit einer zuvor angegebenen ID in seinem Konstruktor Vergleich definiert:

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(); 

Wenn Sie haben andere Klassen in Ihrem Projekt, das IDs verwenden, können Sie diese Funktors Templat machen:

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

Ich habe Ihren Funktor generisch gemacht, damit er mit anderen Typen verwendet werden kann. – leemes

+0

@leemes: Wenn Sie diesen Ansatz gehen, würde ich vorschlagen, auch eine Vorlage für den Datentyp der ID zu verwenden. –

2

Wenn Sie ein Element in STL-Container zu finden, verwenden Sie std::find oder std::find_if Algorithmen Mit C++ 03, die Sie benötigen zu überladen operator == für 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 
} 

oder C++ 11 mit Lambda:

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

Wenn Sie ein bestimmtes Element entfernen möchten, verwenden Sie std::remove_if

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

Auf diese Weise behalten Sie die Logik nicht lokal. Die Definition der Gleichheit von "Freund" -Instanzen kann in einem anderen Szenario unterschiedlich sein. Nur zu sagen ... (Es sollte OK sein, da die ID sowieso eindeutig sein sollte) – leemes

+0

Ja, das ist die Verschönerung von C++ 11 – billz

Verwandte Themen