2010-03-16 16 views
18

Si tengo un stl map de cadena a int y quiero imprimir todos los valores int ordenados, ¿cómo puedo hacer eso?¿Cómo puedo ordenar un mapa por su .segundo parámetro

+0

@Danh El consenso actual es cerrar por la "calidad": Ya que la "calidad" no se puede medir, simplemente voy por votos ascendentes. ;-) Probablemente se deba a qué pregunta golpear las mejores nuevas palabras clave de Google en el título. –

+0

@Danh: En el caso general, eso es cierto: para un 'map ', no es necesariamente cierto que existan comparaciones para 'value_type' . Para el caso específico de 'map ', la comparación por valor es posible. –

Respuesta

24

No se puede ordenar un mapa por sus valores debido a la implementación del mapa.

Si desea emitir los elementos en el mapa en un orden tal ordenada entonces usted tiene que verter primero el contenido del mapa en un vector (por ejemplo) y ordenar ese vector:

template <typename T1, typename T2> 
struct less_second { 
    typedef pair<T1, T2> type; 
    bool operator()(type const& a, type const& b) const { 
     return a.second < b.second; 
    } 
}; 

map<string, int> mymap; 
// … 

vector<pair<string, int> > mapcopy(mymap.begin(), mymap.end()); 
sort(mapcopy.begin(), mapcopy.end(), less_second<string, int>()); 

O, alternativamente, simplemente copie los valores del mapa, deje las claves y clasifique el vector resultante directamente.

+0

Cuando pones ambos 'first' _and_' second' en el vector de todos modos, ¿por qué no ponerlo en un 'std :: map '? – sbi

+0

@sbi: bueno, obviamente porque sería * waaay * demasiado simple y obvio. :-P –

+3

@sbi, los valores pueden repetirse. –

1

No se puede ordenar un mapa, es un contenedor asociativo, no es secuencial, y los contenedores asociados se ordenan por orden interno.

Si solo desea imprimir los valores int, puede ponerlos en un std::vector, ordenar el vector e imprimir los valores.

+0

Creo que quiere imprimir todas las cadenas ordenadas por sus enteros :) –

+0

'std :: map's no están ordenados por 'algunos' ... Se ordenan por valores clave dados explícitamente, en este caso cadenas. –

+0

@malleor: Sí, lo sé. Y un 'std :: unordered_map' está ordenado por otro orden. Escribí sobre "contenedores asociados", no sobre "std :: map" en esa frase. – sbi

3

Si necesita hacer esto varias veces, puede ser más eficiente tener dos contenedores separados, p. su mapa y un contenedor clasificado como set o multiset para almacenar las entradas ordenadas, en lugar de tener que crear un contenedor y ordenarlo sobre la marcha. Pero luego debes mantenerlos sincronizados, lo que podría ser desagradable. Podría encapsular eso envolviéndolos en una clase, o mejor aún usar un boost::multi_index_container.

0

En lugar de utilizar un vector, prefiero simplemente copiándolos en un set<int>:

#include <map> 
#include <set> 
#include <string> 
#include <iostream> 
#include <iterator> 

using namespace std; 

set<int> map2set(map<string, int> const& m) { 
set<int> r; 
for (map<string, int>::const_iterator b = m.begin(), e = m.end(); b != e; ++b) 
    r.insert(b->second); 
return r; 
} 

int main() { 
map<string, int> m; 
m.insert(make_pair("hello", 42)); 
m.insert(make_pair("world", 24)); 
set<int> s = map2set(m); 
copy(s.begin(), s.end(), ostream_iterator<int>(cout, "\n")); 
} 
5

Puede copiar todos los valores en el vector y ordenarla.

#include <algorithm> 
#include <map> 
#include <vector> 

int get_second(pair<string, int> i){ return i.second; } 

int main(int argc, char* argv){ 
    map<string, int> m; 
    m["tt"] = 2; 
    m["rr"] = 1; 
    m["ee"] = 3; 

    vector<int> v(m.size()); 
    transform(m.begin(), m.end(), v.begin(), get_second); 
    sort(v.begin(), v.end()); 
    for (int i=0; i<v.size(); i++) cout << v[i] << endl; 
} 
Cuestiones relacionadas