2010-04-02 10 views
7

Biorąc pod uwagę multimap<A,B> M, w jaki sposób utworzyć vector<B> wszystkich wartości w M za pomocą określonego klucza.Wypełnij wektor wszystkimi wartościami wielowidokowymi z podanym kluczem

np. Biorąc pod uwagę multimapa, w jaki sposób mogę uzyskać wektor wszystkich łańcuchów mapowanych na wartość 123?

Odpowiedź jest łatwa, pętla od dolnej> górnej granicy, ale czy istnieje czysta metoda wolna od pętli?

+0

Jak można dostać się do każdego elementu bez zapętlenie? – GManNickG

+0

stąd pytanie, szukając sztuczek STL/magii (zrobić dla nas pętlę) –

Odpowiedz

4

Oto sposób zrobić styl STL:

// The following define is needed for select2nd with DinkumWare STL under VC++ 
#define _HAS_TRADITIONAL_STL 1 

#include <algorithm> 
#include <vector> 
#include <map> 
#include <string> 
#include <functional> 
#include <map> 
#include <iterator> 
#include <iostream> 

using namespace std; 

void main() 
{ 
    typedef multimap<string, int> MapType; 
    MapType m; 
    vector<int> v; 

    // Test data 
    for(int i = 0; i < 10; ++i) 
    { 
     m.insert(make_pair("123", i * 2)); 
     m.insert(make_pair("12", i)); 
    } 

    MapType::iterator i = m.lower_bound("123"); 
    MapType::iterator j = m.upper_bound("123"); 

    transform(i, j, back_inserter(v), select2nd<MapType::value_type>()); 

    copy(v.begin(), v.end(), ostream_iterator<int>(cout, ",")); 

} 
+0

Więc select2nd nie jest w VC++ 2008? –

+0

Istnieje w nagłówkach Dinkumware dołączonych do VC++ 2008, ale ten i kilka innych znajduje się w #ifdef _HAS_TRADITIONAL_STL ... #endif –

1

Można zainicjować wektor dając jej dwa iteratory, tak:

std::multimap<std::string, std::string> bar; 

... 

std::vector<pair<string,string> > foo(bar.lower_bound("123"), bar.upper_bound("123")); 

ale które daje wektor par (czyli zarówno z klucza i wartości).

Inną opcją byłoby użycie std::copy z czymś takim jak back_inserter, który jest innym sposobem ukrycia pętli, ale z tą samą wadą co powyżej.

std::copy(bar.lower_bound("123"), bar.upper_bound("123"), std::back_inserter(foo)); 

To by dołączyć elementy (jeśli są) do wektora foo.

W celu wydobycia tylko wartości, nie mogę myśleć o pętli nad wynikami, ponieważ nie jestem świadomy standardowego sposobu uzyskania wartości poza zakresem.

+2

Jednym z problemów jest to, że stworzy to "wektor >' a nie 'wektor ' –

+0

Gack. Masz rację, wygląda na to, że podałem prawidłową odpowiedź na niewłaściwe pytanie. –

2

Potrzebujesz i tak pętli. Wszystkie metody "bez pętli" po prostu oddalają pętlę.

#include <map> 
#include <vector> 
#include <algorithm> 
#include <ext/functional> 
using namespace std; 

int main() { 
    multimap<int, double> mm; 
    mm.insert(make_pair(1, 2.2)); 
    mm.insert(make_pair(4, 2.6)); 
    mm.insert(make_pair(1, 9.1)); 
    mm.insert(make_pair(1, 3.1)); 

    vector<double> v; 
    transform(mm.lower_bound(1), mm.upper_bound(1), 
       back_inserter(v), __gnu_cxx::select2nd<pair<int, double> >()); 
    // note: select2nd is an SGI extension. 

    for (vector<double>::const_iterator cit = v.begin(); cit != v.end(); ++ cit) 
     printf("%g, ", *cit); // verify that you've got 2.2, 9.1, 3.1 
    return 0; 
} 
+0

Cóż, oczywiście, że to się rozmywa, to jest sedno pytania! Myślę, że twój asnwer jest rzeczą, której szukałem, ale nie zdawałem sobie sprawy, że select2nd jest niestandardowy. Czy to jest w MSVC++? –

+0

@John: Nie można go znaleźć w witrynie MSDN. Ale łatwo jest napisać funktor 'szablon U select2nd_f (const std :: pair & p) {return p.second; } ' – kennytm

1
template <class Key, class Val> 
vector<Val>& getValues(multimap<Key, Val>& multi, Key& key) 
{ 
    typedef multimap<Key, Val>::iterator imm; 
    static vector<Val> vect; 
    static struct 
    { 
     void operator()(const pair<Key, Val>& p) const 
     { 
      vect.push_back(p.second); 
     } 
    } Push; 

    vect.clear(); 
    pair<imm, imm> range = multi.equal_range(key); 
    for_each(range.first, range.second, Push); 
    return vect; 
} 

Jest nieco wymyślony z powodu swojej 'pętli' nie wymóg.

wolę:

template <class Key, class Val> 
vector<Val> getValues(multimap<Key, Val>& map, Key& key) 
{ 
    vector<Val> result; 
    typedef multimap<Key, Val>::iterator imm; 
    pair<imm, imm> range = map.equal_range(key); 
    for (imm i = range.first; i != range.second; ++i) 
     result.push_back(i->second); 
    return result; 
} 
+0

Dlaczego zwracać odwołanie? Po co ograniczać użytkownika do pracy tylko z jednym kluczem naraz? – kennytm

+0

1. Dlaczego nie? 2. Ponieważ to jest to, o co poprosił OP. –

2

Chodźmy lambda

podane: multimap<A,B> M

wniosek: vector<B> (wszystkie wartości w mz określonego klawisza 'A').

metoda:

Środowisko
std::pair<M::iterator, M::iterator> aRange = M.equal_range('a') 
std::vector<B> aVector; 
std::transform(aRange.first, aRange.second,std::back_inserter(aVector), [](std::pair<A,B> element){return element.second;});   

systemu:

  1. kompilator: gcc (5.3.1-14ubuntu2.1 Ubuntu) 5.3.1 20160413 (z -std = C++ 11)
  2. os: ubuntu 16,04
przykład

Kod:

#include <algorithm> 
#include <vector> 
#include <map> 
#include <string> 
#include <functional> 
#include <iostream> 

int main() 
{ 
    typedef std::multimap<std::string, int> MapType; 
    MapType m; 
    std::vector<int> v; 

    /// Test data 
    for(int i = 0; i < 10; ++i) 
    { 
     m.insert(std::make_pair("123", i * 2)); 
     m.insert(std::make_pair("12", i)); 
    } 

    std::pair<MapType::iterator,MapType::iterator> aRange = m.equal_range("123"); 

    std::transform(aRange.first, aRange.second, std::back_inserter(v), [](std::pair<std::string,int> element){return element.second;}); 

    for(auto & elem: v) 
    { 
     std::cout << elem << std::endl; 
    } 
    return 0; 
} 
Powiązane problemy