
usuario619237
necesito ordenar un std::map
por valor en lugar de por clave. ¿Hay una manera fácil de hacerlo?
Obtuve una solución del siguiente hilo:
std::map ordenar por datos?
¿Hay una solución mejor?
map<long, double> testMap;
// some code to generate the values in the map.
sort(testMap.begin(), testMap.end()); // is there any function like this to sort the map?

Oliver Charlesworth
Aunque ya se han publicado las respuestas correctas, pensé en agregar una demostración de cómo puede hacer esto limpiamente:
template<typename A, typename B>
std::pair<B,A> flip_pair(const std::pair<A,B> &p)
{
return std::pair<B,A>(p.second, p.first);
}
template<typename A, typename B>
std::multimap<B,A> flip_map(const std::map<A,B> &src)
{
std::multimap<B,A> dst;
std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()),
flip_pair<A,B>);
return dst;
}
int main(void)
{
std::map<int, double> src;
...
std::multimap<double, int> dst = flip_map(src);
// dst is now sorted by what used to be the value in src!
}
Fuente asociativa genérica (requiere C++11)
Si está utilizando una alternativa a std::map
para el contenedor asociativo de origen (como std::unordered_map
), podría codificar una sobrecarga separada, pero al final la acción sigue siendo la misma, por lo que se puede usar un contenedor asociativo generalizado que usa plantillas variadas para cualquiera construcción de mapeo:
// flips an associative container of A,B pairs to B,A pairs
template<typename A, typename B, template<class,class,class...> class M, class... Args>
std::multimap<B,A> flip_map(const M<A,B,Args...> &src)
{
std::multimap<B,A> dst;
std::transform(src.begin(), src.end(),
std::inserter(dst, dst.begin()),
flip_pair<A,B>);
return dst;
}
Esto funcionará para ambos std::map
y std::unordered_map
como la fuente del flip.

nielw
Necesitaba algo similar, pero el mapa invertido no funcionaría para mí. Simplemente copié mi mapa (frecuencia a continuación) en un vector de pares, luego clasifiqué los pares como quería.
std::vector<std::pair<int, int>> pairs;
for (auto itr = freq.begin(); itr != freq.end(); ++itr)
pairs.push_back(*itr);
sort(pairs.begin(), pairs.end(), [=](std::pair<int, int>& a, std::pair<int, int>& b)
{
return a.second < b.second;
}
);
Si desea presentar los valores en un mapa en orden, copie los valores del mapa al vector y ordene el vector.
Me gusta la respuesta de Oli (voltear un mapa), pero parece que tiene un problema: el mapa contenedor no permite dos elementos con la misma clave.
Una solución es hacer que dst sea del tipo multimapa. Otro es volcar src en un vector y ordenar el vector. El primero requiere modificaciones menores a la respuesta de Oli, y el último se puede implementar utilizando la copia STL de manera concisa.
#include <iostream>
#include <utility>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
map<int, int> m;
m[11] = 1;
m[22] = 2;
m[33] = 3;
vector<pair<int, int> > v;
copy(m.begin(),
m.end(),
back_inserter<vector<pair<int, int> > >(v));
for (size_t i = 0; i < v.size(); ++i) {
cout << v[i].first << " , " << v[i].second << "\n";
}
return 0;
};

ericgrosse
Para construir sobre la solución de Oli (https://stackoverflow.com/a/5056797/2472351) usando mapas múltiples, puede reemplazar las dos funciones de plantilla que usó con lo siguiente:
template <typename A, typename B>
multimap<B, A> flip_map(map<A,B> & src) {
multimap<B,A> dst;
for(map<A, B>::const_iterator it = src.begin(); it != src.end(); ++it)
dst.insert(pair<B, A>(it -> second, it -> first));
return dst;
}
Aquí hay un programa de ejemplo que muestra todos los pares clave-valor que se conservan después de realizar el cambio.
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
template <typename A, typename B>
multimap<B, A> flip_map(map<A,B> & src) {
multimap<B,A> dst;
for(typename map<A, B>::const_iterator it = src.begin(); it != src.end(); ++it)
dst.insert(pair<B, A>(it -> second, it -> first));
return dst;
}
int main() {
map<string, int> test;
test["word"] = 1;
test["spark"] = 15;
test["the"] = 2;
test["mail"] = 3;
test["info"] = 3;
test["sandwich"] = 15;
cout << "Contents of original map:\n" << endl;
for(map<string, int>::const_iterator it = test.begin(); it != test.end(); ++it)
cout << it -> first << " " << it -> second << endl;
multimap<int, string> reverseTest = flip_map(test);
cout << "\nContents of flipped map in descending order:\n" << endl;
for(multimap<int, string>::const_reverse_iterator it = reverseTest.rbegin(); it != reverseTest.rend(); ++it)
cout << it -> first << " " << it -> second << endl;
cout << endl;
}
Resultado:

No puedes ordenar un std::map
de esta manera, porque las entradas en el mapa están ordenadas por clave. Si desea ordenar por valor, debe crear una nueva std::map
con clave y valor intercambiados.
map<long, double> testMap;
map<double, long> testMap2;
// Insert values from testMap to testMap2
// The values in testMap2 are sorted by the double value
Recuerde que las claves dobles deben ser únicas en testMap2
o usar std::multimap
.

Comunidad
A std::map
ordenados por su valor es en esencia un std::set
. Con mucho, la forma más fácil es copiar todas las entradas en el mapa a un conjunto (tomado y adaptado de aquí)
template <typename M, typename S>
void MapToSet( const M & m, S & s )
{
typename M::const_iterator end = m.end();
for( typename M::const_iterator it = m.begin(); it != end ; ++it )
{
s.insert( it->second );
}
}
Una advertencia: si el mapa contiene diferentes claves con el mismo valor, no se insertarán en el conjunto y se perderán.
¿Por qué necesita el mapa ordenado de esa manera? ¿Está tratando de mejorar el tiempo de búsqueda o desea recorrerlo de cierta manera?
–Matt Curtis
20 de febrero de 2011 a las 11:18
Puede cambiar la clave con el valor.
– Pawel Zubrycki
20 de febrero de 2011 a las 13:17
Posible duplicado del mapa STL–> ¿ordenar por valor?
– Ciro Santilli Путлер Капут 六四事
1 de enero de 2017 a las 14:20