найти в std::vector‹std::pair›

У меня есть вектор пар. Первый в паре имеет тип std::string, а второй — тип Container.

Какие удобные функции существуют в std или boost, чтобы я мог вернуть контейнер, учитывая строковое значение в качестве ключа?

ОБНОВЛЕНИЕ

Было отмечено, что вместо этого я мог бы использовать std::map, но на самом деле мне нужно сохранить порядок моих элементов в том порядке, в котором я помещаю их в вектор.


person Baz    schedule 19.03.2013    source источник
comment
В таком случае, почему std::vector, а не std::map?   -  person Kiril Kirov    schedule 19.03.2013
comment
std::find_if и пользовательский предикат (лямбда в C++11)   -  person Andy Prowl    schedule 19.03.2013
comment
@Andy Prowl Я пометил свой вопрос как c++98   -  person Baz    schedule 19.03.2013
comment
@meh Мне нужно сохранить порядок элементов в векторе   -  person Baz    schedule 19.03.2013
comment
@Baz: Извините, я пропустил тег. Ну, ответ тот же, за исключением части в скобках   -  person Andy Prowl    schedule 19.03.2013
comment
Принимая во внимание этот и другой ваш вопрос, вероятно, было бы лучше, если бы вы задали один вопрос о контейнере, который поддерживает поиск как по строковому ключу, так и по порядку вставки. На каждую половину этого вопроса легко ответить по отдельности (использовать карту/использовать вектор), но их комбинация усложняет задачу.   -  person MSalters    schedule 19.03.2013
comment
Почему бы не использовать std::map<std::string,std::vector<Container>>?   -  person wjl    schedule 11.11.2014


Ответы (4)


Возможное решение:

struct comp
{
    comp(std::string const& s) : _s(s) { }

    bool operator () (std::pair<std::string, Container> const& p)
    {
        return (p.first == _s);
    }

    std::string _s;
};

// ...

typedef std::vector<std::pair<std::string, Container> > my_vector;
my_vector v;

// ...

my_vector::iterator i = std::find_if(v.begin(), v.end(), comp("World"));
if (i != v.end())
{
    Container& c = i->second;
}

// ...

Вот полный пример:

#include <vector>
#include <utility>
#include <string>
#include <algorithm>

struct Container
{
    Container(int c) : _c(c) { }
    int _c;
};

struct comp
{
    comp(std::string const& s) : _s(s) { }

    bool operator () (std::pair<std::string, Container> const& p)
    {
        return (p.first == _s);
    }

    std::string _s;
};

#include <iostream>

int main()
{
    typedef std::vector<std::pair<std::string, Container> > my_vector;
    my_vector v;
    v.push_back(std::make_pair("Hello", Container(42)));
    v.push_back(std::make_pair("World", Container(1729)));
    my_vector::iterator i = std::find_if(v.begin(), v.end(), comp("World"));
    if (i != v.end())
    {
        Container& c = i->second;
        std::cout << c._c; // <== Prints 1729
    }
}

А вот и живой пример.

person Andy Prowl    schedule 19.03.2013
comment
может показаться, что ссылка на живой пример не работает - person Erik; 24.09.2016

Использование Boost. Диапазон и Boost.Bind , ты можешь это сделать:

struct predicate
{
    template<class Key, class Pair>
    bool operator()(const Key& k, const Pair& p) const
    {
        return p.first == k;
    }
};

// Your vector of pairs
std::vector<std::pair<std:string, Container> v = ...;
// The key you would like to search for
std::string key = ...;
Container& c = boost::find_if(v, boost::bind(predicate(), key, _1))->second;
person Paul Fultz II    schedule 19.03.2013
comment
В таком случае можно было бы заменить boost::bind на std::bind1st и таким образом избавиться от буста. - person qdii; 19.03.2013

Есть простое решение: используйте std::copy и std::inserter:

#include <algorithm>
#include <map>
#include <string>
#include <utility> // pair
#include <vector>

void function()
{
    typedef int Data;
    typedef std::pair< std::string, Data > String_Data_Pair;
    typedef std::vector< String_Data_Pair > String_Data_Pair_Sequence;
    typedef std::map< std::string, Data > String_To_Data_Map;

    String_Data_Pair_Sequence string_data_pairs;

    /* fill 'string_data_pairs' here */

    String_To_Data_Map string_to_data_map;

    std::copy( string_data_pairs.begin(),
               string_data_pairs.end(),
               std::inserter( string_to_data_map,
                              string_to_data_map.begin() /* superfluous, but required */ ) );
}
person Charles L Wilcox    schedule 19.03.2013
comment
Нельзя ли просто заменить копию на String_To_Data_Map string_to_data_map(string_data_pairs.begin(), string_data_pairs.end());? - person Steve Jessop; 19.03.2013
comment
Да... да, ты можешь. Иногда я забываю о конструкторах на основе диапазона. - person Charles L Wilcox; 19.03.2013

class SomeClass{
   int num;
public:
   SomeClass();
   void setNumber(int n) const { num = n;}
};

vector<pair<SomeClass,string> > vectr;

for(unsigned int i = 0; i < vectr.size(); i++)
   if(vectr[i].second == "key")
       vectr[i].first.setNumber(50);

Работал на меня!

person Stefan Matta    schedule 10.11.2014