c++ - example - multimap insert
stl:: multimap: ¿cómo obtengo grupos de datos? (6)
Multimap esencialmente tiene grupos de datos ordenados por la clave. Quiero un método por el que pueda acceder a estos grupos individuales y obtener sus valores agregados. Por ejemplo, en una tienda std::multimap< string, int >
I store
{"Group1", 1},
{"Group1", 2},
{"Group1", 3},
{"Group2", 10},
{"Group2", 11},
{"Group2", 12}
Habiendo almacenado estos valores, debería ser capaz de iterar este multimapa y obtener los valores agregados de cada "grupo". El problema es que no hay funciones definidas en STL para acceder a MultiMaps de tal manera. Podría usar lower_bound
, upper_bound
para iterar manualmente el multimap y sumar los contenidos del grupo, pero espero que haya mejores formas ya definidas en STL. ¿Alguien puede proponer una solución sobre cómo podría obtener los valores agregados para un grupo en el ejemplo anterior?
No es una respuesta multimapa, pero puede hacer las siguientes cosas si así lo desea.
#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";
}
}
}
Puede usar un contenedor alternativo que puede contener las sumas agregadas de cada grupo. Para hacer esto, puede hacer 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
Por supuesto, si tiene Lambda (en C ++ 0x) podría ser más 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;
}
);
Si ya conoce las claves, puede usar multimap::equal_range
para obtener los iteradores al principio y al final del grupo; use cualquier algoritmo estándar para obtener los resultados deseados del rango. Si no conoce las claves, puede comenzar desde el begin()
e iterar por ellas, comparando las claves para encontrar el inicio de cada grupo nuevo.
// 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
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.
pair<Iter, Iter> range = my_multimap.equal_range("Group1");
int total = accumulate(range.first, range.second, 0);
Es de una manera.
Editar:
Si no conoce el grupo que está buscando y solo está examinando cada grupo, puede obtener el rango del siguiente grupo de la siguiente manera:
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>());