2013-03-20 20 views
19

Próbuję znaleźć ładny sposób na znalezienie indeksu określonego obiektu w wektorze - porównując ciąg do pola elementu w obiekcie.Wyszukiwanie wektora obiektów według atrybutów obiektu

Like this : find(vector.begin(), vector.end(), [object where obj.getName() == myString]) 

Szukałem bez powodzenia - może nie rozumiem w pełni czego szukać.

+1

Czy może być więcej niż jeden obiekt o tej samej nazwie? Czy chcesz je wszystkie znaleźć? –

Odpowiedz

36

Możesz użyć std::find_if z odpowiednim funktorem. W tym przykładzie C++ 11 lambda jest stosowany:

std::vector<Type> v = ....; 
std::string myString = ....; 
auto it = find_if(v.begin(), v.end(), [&myString](const Type& obj) {return obj.getName() == myString;}) 

if (it != v.end()) 
{ 
    // found element. it is an iterator to the first matching element. 
    // if you really need the index, you can also get it: 
    auto index = std::distance(v.begin(), it); 
} 

Jeśli nie masz C++ 11 wsparcie lambda, funktorem będzie działać:

struct MatchString 
{ 
MatchString(const std::string& s) : s_(s) {} 
bool operator()(const Type& obj) const 
{ 
    return obj.getName() == s_; 
} 
private: 
    const std::string& s_; 
}; 

tutaj MatchString to typ, którego instancje można wywoływać za pomocą pojedynczego obiektu Type i zwracać wartość logiczną. Na przykład,

Type t("Foo"); // assume this means t.getName() is "Foo" 
MatchString m("Foo"); 
bool b = m(t); // b is true 

potem można przekazać instancję do std::find

std::vector<Type>::iterator it = find_if(v.begin(), v.end(), MatchString(myString)); 
+0

Musisz użyć 'find_if', jeśli używasz funktora. – Peter

+0

@Peter dobry połów, dzięki! – juanchopanza

5

Oprócz Lambda i odręcznym funktora używanego przez Juancho, masz możliwość korzystania boost::bind (C++ 03) lub std::bind (C++ 11) i prostą funkcją:

bool isNameOfObj(const std::string& s, const Type& obj) 
{ return obj.getName() == s; } 

//... 
std::vector<Type>::iterator it = find_if(v.begin(), v.end(), 
    boost::bind(&isNameOfObj, myString, boost::placeholders::_1)); 

lub jeśli Type ma metodę isName:

std::vector<Type>::iterator it = find_if(v.begin(), v.end(), 
    boost::bind(&Type::isName, boost::placeholders::_1, myString)); 

To jest tylko dla kompletności. W C++ 11 wolałbym Lambdas, w C++ 03 używałbym bind tylko wtedy, gdy sama funkcja porównania już istnieje. Jeśli nie, wolę funktora.

PS: Ponieważ C++ 11 nie ma polimorficznych/szablonowych lambd, bind nadal ma swoje miejsce w C++ 11, np. jeśli typy parametrów są nieznane, trudne do przeliterowania lub w inny sposób niełatwe do dedukcji.

2

Pomocny może być prosty iterator.

typedef std::vector<MyDataType> MyDataTypeList; 
// MyDataType findIt should have been defined and assigned 
MyDataTypeList m_MyObjects; 
//By this time, the push_back() calls should have happened 
MyDataTypeList::iterator itr = m_MyObjects.begin(); 
while (itr != m_MyObjects.end()) 
{ 
    if(m_MyObjects[*itr] == findIt) // any other comparator you may want to use 
    // do what ever you like 
} 
Powiązane problemy