Wyszukiwanie wektora obiektów według atrybutu obiektu

Próbuję znaleźć dobry sposób na znalezienie indeksu określonego obiektu w wektorze-porównując łańcuch znaków do pola elementu w obiekcie.

Tak:

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

Szukałem bez powodzenia - może nie do końca rozumiem czego szukać.

Author: Christoffer, 2013-03-20

3 answers

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

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 obsługi lambda C++11, funktor 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 jest typem, którego instancje można wywołać 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

Następnie możesz przekazać instancję do std::find

std::vector<Type>::iterator it = find_if(v.begin(), v.end(), MatchString(myString));
 63
Author: juanchopanza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-30 16:04:56

Oprócz Lambda i odręcznego funktora używanego przez juancho, masz możliwość użycia boost::bind (C++03) lub std::bind (C++11) oraz prostej funkcji:

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 tylko dla kompletności. W C++11 wolałbym Lambda, w C++03 użyłbym bind tylko wtedy, gdy sama funkcja porównawcza już istnieje. Jeśli nie, preferuj funkcję.

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

 7
Author: Arne Mertz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-20 08:54:36

Prosty iterator może pomóc.

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
}
 4
Author: uniqrish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-20 11:00:27