Question

Multimap contient essentiellement des groupes de données triés par clé. Je veux une méthode par laquelle je pourrais accéder à ces groupes individuels et obtenir leurs valeurs globales. Par exemple, dans un std::multimap< string, int > je stocke

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

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

Après avoir stocké ces valeurs, je devrais pouvoir itérer cette carte et obtenir les valeurs globales de chaque & "groupe &"; Le problème est qu'il n'y a pas de fonction définie dans STL permettant d'accéder à MultiMaps de cette manière. Je pourrais utiliser lower_bound, upper_bound pour itérer manuellement la carte multiple et totaliser le contenu du groupe, mais j'espère qu'il pourrait y avoir de meilleures façons déjà définies dans STL? Quelqu'un peut-il proposer une solution pour obtenir les valeurs d'agrégation d'un groupe dans l'exemple ci-dessus?

Était-ce utile?

La solution

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

Est à sens unique.

Modifier:

Si vous ne connaissez pas le groupe que vous recherchez et que vous ne faites que parcourir chaque groupe, vous pouvez obtenir la plage du groupe suivant comme suit:

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

Autres conseils

// 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

Si vous connaissez déjà les clés, vous pouvez utiliser multimap::equal_range pour amener les itérateurs au début et à la fin du groupe; utilisez n'importe quel algorithme standard pour obtenir les résultats souhaités de la plage. Si vous ne connaissez pas les clés, vous pouvez commencer à begin() et les parcourir vous-même, en comparant les clés pour trouver le début de chaque nouveau groupe.

Vous pouvez utiliser un autre conteneur pouvant contenir les sommes agrégées de chaque groupe. Pour ce faire, vous pourriez faire quelque chose comme:

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

Bien sûr, si vous avez Lambda (en C ++ 0x), cela pourrait être plus simple:

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

Syntaxe:

#include <map>
pair<iterator, iterator> equal_range( const key_type& key );

La fonction equal_range() renvoie deux itérateurs - l'un sur le premier élément contenant la clé, l'autre sur un point situé juste après le dernier élément contenant la clé.

Ce n'est pas une réponse multi-map, mais vous pouvez faire les choses suivantes si vous le souhaitez.

#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";
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top