2008-10-29 15 views
31

Multimap zasadniczo zawiera grupy danych posortowane według klucza. Chcę mieć metodę, dzięki której mógłbym uzyskać dostęp do tych pojedynczych grup i uzyskać ich zagregowane wartości. Na przykład, w std::multimap< string, int > przechowywaćstl :: multimap - jak uzyskać grupy danych?

{"Group1", 1}, 
{"Group1", 2}, 
{"Group1", 3}, 

{"Group2", 10}, 
{"Group2", 11}, 
{"Group2", 12} 

Po przechowywane te wartości powinny być w stanie iteracyjne tej multimap i uzyskać łączne wartości każdego „grupy”. Problem polega na tym, że nie ma żadnych funkcji zdefiniowanych w STL, aby uzyskać dostęp do MultiMaps w taki sposób. Mogę użyć lower_bound, upper_bound do ręcznego iterowania multimapy i sumowania zawartości grupy, ale mam nadzieję, że mogą być lepsze sposoby już zdefiniowane w STL? Czy ktoś może zaproponować rozwiązanie, w jaki sposób mogę uzyskać zagregowane wartości dla grupy w powyższym przykładzie.

+0

Bardzo elegancki i Metoda lambda opisana tutaj: http://stackoverflow.com/a/37680747/5516759 –

Odpowiedz

38
pair<Iter, Iter> range = my_multimap.equal_range("Group1"); 
int total = accumulate(range.first, range.second, 0); 

To jeden sposób.

Edit:

Jeśli nie wiesz grupę, której szukasz, i są po prostu przechodzi każdej grupy, coraz gamę następnej grupy można zrobić tak:

template <typename Pair> 
struct Less : public std::binary_function<Pair, Pair, bool> 
{ 
    bool operator()(const Pair &x, const Pair &y) const 
    { 
     return x.first < y.first; 
    } 
}; 

Iter first = mmap.begin(); 
Iter last = adjacent_find(first, mmap.end(), Less<MultimapType::value_type>()); 
+0

Czy nie powinna to być 'x.first == y.first;'? Dlaczego użyłeś 'operatora <'? Zgodnie z [dokumentem] (http://www.cplusplus.com/reference/algorithm/adjacent_find/) parametru "adjacent_find", parametr predykatu powinien zwracać wynik porównania z wartością true (niezerową), co oznacza, że ​​są być uznanym za równy, a fałszywy (zero) za nie-równy. Dlaczego powracasz do rzeczywistości, aby uzyskać wynik nierównomierny? – Meysam

+2

Tak, wydaje się to błędem. 'adjacent_find' oczekuje" równego "predykatu. Jestem także pewien, że istnieje 'std :: equal_to ' gotowy do użycia. – leemes

+0

@ Wydaje mi się, że twoja edycja zmienia zachowanie na nieprawidłowe. Operator "Mniej niż" miał znaleźć ostatni element przed zmianą klucza (może to być 'awans do 1 na pierwszy element z nowym kluczem), podczas gdy z operatorem równości, po prostu powróci iterator do tego samego (' pierwszy ') element – slawekwin

10

Jeśli znasz już klucze, możesz użyć multimap::equal_range, aby przenieść iteratory na początek i na koniec grupy; użyj dowolnego standardowego algorytmu, aby uzyskać pożądane wyniki z zakresu. Jeśli nie znasz kluczy, możesz zacząć od begin() i samemu przeglądać je, porównując klucze, aby znaleźć początek każdej nowej grupy.

-1

Nie jest to odpowiedź typu "wiele map", ale możesz wykonać następujące czynności, jeśli sobie tego życzysz.

#include <iostream> 
#include <vector> 
#include <map> 
#include <string> 
#include <boost/assign/list_of.hpp> 
#include <boost/foreach.hpp> 
using namespace std; 
using namespace boost; 
using namespace boost::assign; 

int main() { 
    typedef map<string, vector<int> > collection; 
    collection m; 
    m["Group 1"] = list_of(1)(2)(3); 
    m["Group 2"] = list_of(10)(11)(12); 
    collection::iterator g2 = m.find("Group 2"); 
    if (g2 != m.end()) { 
     BOOST_FOREACH(int& i, g2->second) { 
      cout << i << "\n"; 
     } 
    } 
} 
1

Można użyć alternatywnego kontenera, który może zawierać zagregowane sumy każdej grupy. Aby to zrobić, można zrobić coś takiego:

template <class KeyType, class ValueType> 
struct group_add { 
    typedef map<KeyType, ValueType> map_type; 
    map_type & aggregates; 
    explicit group_add(map_type & aggregates_) 
    : aggregates(aggregates_) { }; 
    void operator() (map_type::value_type const & element) { 
    aggregates[element.first] += element.second; 
    }; 
}; 

template <class KeyType, class ValueType> 
group_add<KeyType, ValueType> 
make_group_adder(map<KeyType, ValueType> & map_) { 
    return group_add<KeyType, ValueType>(map_); 
}; 

// ... 
multimap<string, int> members; 
// populate members 
map<string, int> group_aggregates; 
for_each(members.begin(), members.end(), 
    make_group_adder(group_aggregates)); 
// group_aggregates now has the sums per group 

oczywiście, jeśli masz Lambda (w C++ 0x) mogłoby być prostsze:

multimap<string, int> members; 
map<string, int> group_aggregates; 
for_each(members.begin(), members.end(), 
    [&group_aggregates](multimap<string, int>::value_type const & element) { 
    group_aggregates[element.first] += element.second; 
    } 
); 
19
// samekey.cpp -- Process groups with identical keys in a multimap 

#include <iostream> 
#include <string> 
#include <map> 
using namespace std; 

typedef multimap<string, int> StringToIntMap; 
typedef StringToIntMap::iterator mapIter; 

int main() 
{ 
    StringToIntMap mymap; 

    mymap.insert(make_pair("Group2", 11)); 
    mymap.insert(make_pair("Group1", 3)); 
    mymap.insert(make_pair("Group2", 10)); 
    mymap.insert(make_pair("Group1", 1)); 
    mymap.insert(make_pair("Group2", 12)); 
    mymap.insert(make_pair("Group1", 2)); 

    cout << "mymap contains:" << endl; 

    mapIter m_it, s_it; 

    for (m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it) 
    { 
     string theKey = (*m_it).first; 

     cout << endl; 
     cout << " key = '" << theKey << "'" << endl; 

     pair<mapIter, mapIter> keyRange = mymap.equal_range(theKey); 

     // Iterate over all map elements with key == theKey 

     for (s_it = keyRange.first; s_it != keyRange.second; ++s_it) 
     { 
      cout << " value = " << (*s_it).second << endl; 
     } 
    } 

    return 0; 

} // end main 

// end samekey.cpp 
+1

Zobacz też: http://stackoverflow.com/a/9371314/19501 –

0
equal_range 
Syntax:  
#include <map> 
pair<iterator, iterator> equal_range(const key_type& key); 
The function equal_range() returns two iterators - one to the first 
element that contains key, another to a point just after the last 
element that contains key. 
Powiązane problemy