2013-03-19 24 views
10

Mam wektor par. Pierwszy w parze jest typu std :: string, a drugi jest typu Container.znaleźć w std :: wektor <std::pair>

Jaką wygodną funkcję można uzyskać w trybie standardowym lub doładowania, aby można było zwrócić kontener podając wartość ciągu jako klucz?

UPDATE

Został on powiedział, że mogę użyć std :: map zamiast, ale faktycznie trzeba zachować kolejność moich przedmiotów, w takiej kolejności, wciskam je do wektora.

+3

W tym przypadku, dlaczego 'std :: vector', a nie' std :: map'? –

+2

'std :: find_if' i niestandardowy predykat (lambda w C++ 11) –

+0

@Andy Prowl Zaznaczam moje pytanie jako C++ 98 – Baz

Odpowiedz

7

Możliwym rozwiązaniem:

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; 
} 

// ... 

Powyżej znajduje się pełna przykład:

#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 
    } 
} 

A oto live example.

+0

wydaje się, że link do żywego przykładu jest zepsuty. – Erik

1

Korzystanie Boost.Range i Boost.Bind, można to zrobić:

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; 
+0

W takim przypadku możliwe byłoby zastąpienie 'boost :: bind' przez' std :: bind1st' i pozbycie się w ten sposób boostu. – qdii

0

Istnieje proste rozwiązanie: użyć std::copy i 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 */)); 
} 
+1

Nie możesz po prostu zamienić kopii na 'String_To_Data_Map string_to_data_map (string_data_pairs.begin(), string_data_pairs.end());'? –

+0

Tak ... tak, możesz. Czasami zapominam o konstruktorach opartych na zasięgu. –

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

pracował dla mnie!

Powiązane problemy