Si j'ai une carte stl de chaîne à int et que je veux imprimer toutes les valeurs int triées - comment puis-je faire cela?Comment puis-je trier une carte par son paramètre .second
Répondre
Vous ne pouvez pas trier une carte par ses valeurs en raison de l'implémentation de la carte.
Si vous voulez émettre les éléments de la carte dans un tel ordre de tri alors vous devez d'abord vider le contenu de carte dans un vecteur (par exemple) et trier ce vecteur:
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>());
Ou bien, tout simplement copier les valeurs de la carte, en laissant les clés, et trier le vecteur résultant directement.
Quand vous mettez de toute façon 'first' _and_' second' dans le vecteur, pourquoi ne pas le mettre dans un 'std :: map
@sbi: bien évidemment parce que ce serait * waaay * trop simple et évident. :-P –
@sbi, les valeurs peuvent être répétées. –
Vous ne pouvez pas trier une carte, c'est un conteneur associatif, pas un conteneur séquentiel, et les conteneurs associés sont triés par ordre interne.
Si vous souhaitez imprimer uniquement les valeurs int
, vous pouvez les mettre dans un std::vector
, trier le vecteur et imprimer les valeurs.
Je pense qu'il veut imprimer toutes les chaînes triées par leurs ints :) –
Les 'std :: map' ne sont pas triés par 'un certain' ordre. Ils sont triés par des valeurs de clé explicitement données, dans ce cas des chaînes. –
@malleor: Oui, je sais. Et un 'std :: unordered_map' est trié par un autre ordre. J'ai écrit à propos de _associated containers_, pas à propos de 'std :: map' dans cette phrase. – sbi
Vous ne pouvez pas faire cela automatiquement. std::map
utilise la première valeur (nomen omen 'key') pour trier le contenu. Au lieu de cela, vous pouvez utiliser boost::multi_index_container
.
Si vous devez le faire plusieurs fois, il peut être plus efficace de conserver deux conteneurs séparés, par ex. votre carte et un conteneur trié comme set
ou multiset
pour stocker les ints triés, plutôt que de devoir créer un conteneur et le trier à la volée. Mais alors vous devez les garder synchronisés, ce qui pourrait devenir mucky. Vous pourriez encapsuler cela en les enveloppant dans une classe, ou mieux encore utiliser un boost::multi_index_container
.
Au lieu d'utiliser un vector
, je préfère simplement les copier sur 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"));
}
Vous pouvez copier toutes les valeurs dans le vecteur et le tri.
#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;
}
@Danh Le consensus actuel est de près par "qualité":
@Danh: Dans le cas général c'est vrai - pour un 'map', il n'est pas nécessairement vrai que des comparaisons existent même pour 'valeur_type' . Pour le cas spécifique de «map », une comparaison par valeur est possible. –