Pergunta

Multimap tem essencialmente grupos de dados ordenados pela chave. Eu quero um método pelo qual eu poderia acessar esses grupos individuais e obter seus valores agregados. Por exemplo, em uma loja std::multimap< string, int > I

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

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

Depois de ter armazenado esses valores, eu deveria ser capaz de interagir este multimap e obter os valores agregados de cada "grupo". O problema é que não existem quaisquer funções definidas em STL para MultiMaps de acesso de tal maneira a. Eu poderia usar lower_bound, upper_bound iterar manualmente o multimap eo total conteúdo do grupo, mas eu estou esperando que poderia haver melhores formas já definidas no STL? Alguém pode propor uma solução de como eu poderia obter os valores agregados para um grupo no exemplo acima.

Foi útil?

Solução

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

é um caminho.

Editar:

Se você não sabe o grupo que você está procurando, e estão apenas passando por cada grupo, ficando gama do próximo grupo pode ser feito assim:

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

Outras dicas

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

Se você já sabe as chaves, você pode usar multimap::equal_range para obter os iteradores para o início eo fim do grupo; usar qualquer algoritmo padrão para obter os resultados desejados a partir do intervalo. Se você não sabe as chaves, você pode começar em begin() e iterate através deles mesmo, comparando chaves para encontrar o início de cada novo grupo.

É possível utilizar um recipiente alternativo que pode conter as somas agregados de cada grupo. Para fazer isso você pode fazer algo como:

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

Claro que, se você tem de Lambda (em C ++ 0x) poderia ser mais simples:

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

Sintaxe:

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

A função equal_range() retornos dois iteradores - uma para o primeiro elemento que contém a chave, outro para um ponto logo após o último elemento que contém a chave.

Não é uma resposta multimap, mas você pode fazer coisas como o seguinte, se assim escolherem.

#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";
        }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top