2013-01-08 7 views
13

Jestem bardzo nowy w języku C++ i próbuję znaleźć sposób na wyszukiwanie wektorów struktur dla struktury z pewnymi danymi członków.Wyszukaj element struct w wektorze według danych członka

wiem, że to będzie działać z typów prostych w wektorze

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

Ale powiedzmy, że mam struct tak:

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

oraz wektor takiego:

vector<Friend> friends; 

Następnie wektor jest pełen przyjaciół.

Załóżmy, że chcę wyszukać przyjaciela z określonym identyfikatorem i podać szczegóły. Lub usuń określoną strukturę z wektora. Czy istnieje prosty sposób na zrobienie tego?

Odpowiedz

19

Można to zrobić z std::find_if i predykatem wyszukiwania, które mogą być wyrażone jako funkcja lambda, jeśli masz C++ 11 (lub C++ 0x) dostępny:

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

Aby użyć identyfikatora podana jako zmienna, trzeba wychwytywania to w wyrażeniu lambda (w [...]):

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

Jeśli nie masz C++ 11 dostępne, trzeba zdefiniować predykat jako funktora (obiekt funkcji). Remy Lebeau's answer używa tego podejścia.

Aby usunąć elementy spełniające kryteria zdefiniowane w predykacie, należy użyć remove_if zamiast find_if (pozostała składnia jest taka sama).

Aby uzyskać więcej algorytmów, zobacz the STL <algorithm> reference.

+0

Jest to miły zwyczaj auto! – DanDan

+0

@DanDan Tak, czasami nie chcę definiować lambda bezpośrednio tam, gdzie jest używana jako argument funkcji (powoduje to, że linia jest tak długa) – leemes

+0

dlaczego pierwszy używa '.begin()' i drugi ' std :: begin'? –

4

można używać w połączeniu z std::find_if funktorów (jeśli pracujesz z C++ 98) lub lambda (jeśli używasz C++ 11, które zakładam):

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

Zastosowanie std::find_if() . @leemes i @AndyProwl pokazali, jak go używać w kompilatorze C++ 11.Ale jeśli nie używasz kompilatora C++ 11, a następnie można go używać tak zamiast, który definiuje funktor porównujące identyfikator danego elementu z wcześniej określonym ID w jego konstruktora:

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

Jeśli masz inne zajęcia w projekcie, które używają identyfikatorów, można zrobić to funktor matrycy:

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

Zrobiłem twój funktor ogólny, więc może być używany z innymi typami. – leemes

+0

@leemes: Jeśli wybierzesz to podejście, sugerowałbym użycie szablonu dla typu danych ID również. –

2

Jeśli chcesz znaleźć element w kontenerze STL, użyj std::find lub std::find_if algorytmy z C++ 03, trzeba przeciążać operatora == dla 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 
} 

lub C++ 11 z lambda:

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

Jeśli chcesz usunąć pewien element, użyj std::remove_if

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

W ten sposób nie zachowujesz logiki lokalnie. Definicja równości instancji "Friend" może być inna w innym scenariuszu. Po prostu mówię ... (Powinno być OK, ponieważ identyfikator powinien być unikalny) i tak jest – leemes

+0

tak, to jest upiększenie z C++ 11 – billz

Powiązane problemy