std :: map avec les clés std :: pair où les éléments de paire n’ont pas d’importance d’ordre

Comme le dit la question, j’ai besoin d’utiliser std :: map de telle manière que.

std::map<std::pair, int*> m; int* a_ptr = new int; *a_ptr = 15; m[std::make_pair(1, 2)] = a_ptr; std::cout << *m[std::make_pair(2, 1)] << std::endl; //should output 15 

Maintenant, dans mon implémentation actuelle, toutes les clés et valeurs sont en réalité des pointeurs. Comment devrais-je aborder ce problème?

Deux idées me viennent à l’esprit.

  1. La première est que je devrais écrire une fonction qui chaque fois que j’utilise m[] pour accéder ou écrire dans la carte, je devrais aussi m.find() vérifier la combinaison des autres paires et agir en conséquence.

  2. Other utilise std :: unordered_map avec un hasher personnalisé qui ne fait aucune différence lorsque les positions des éléments de la pair sont permutées. (Je ne sais pas comment faire cela. Si je multiplie ou ajoute les deux pointeurs, le résultat ne sera pas égal. Besoin d’aide si c’est le chemin à parcourir.)

Si vous pouvez penser à une meilleure méthode, je serai heureux de l’entendre, sinon j’ai indiqué ce que j’avais besoin d’aide dans le deuxième article. (ce qui, à mon avis, est plus efficace, le premier n’est pas beau)

Merci.

Pourriez-vous simplement vous assurer que les paires sont toujours dans le même ordre? Utilisez une fonction d’assistance, comme:

 std::pair my_make_pair(int a, int b) { if ( a < b ) return std::pair(a,b); else return std::pair(b,a); } 

et utilisez-le toujours pour accéder à la carte:

 m[my_make_pair(1,2)] = a_ptr; std::cout << m[my_make_pair(2, 1)] << std::endl; 

Il suffit d’utiliser un comparateur personnalisé

 [](std::pair const& lhs, std::pair const& rhs) { int lhs_min = std::min(lhs.first, lhs.second); int lhs_max = std::max(lhs.first, lhs.second); int rhs_min = std::min(rhs.first, rhs.second); int rhs_max = std::max(rhs.first, rhs.second); return lhs_min < rhs_min || (!(rhs_min < lhs_min) && lhs_max < rhs_max) } 

Comment cela marche-t-il?

Les premières lignes classent de manière déterministe les 2 éléments d’un couple; c'est-à-dire que vous pouvez les fournir dans l'un ou l'autre ordre et que lhs_min & lhs_max seront les mêmes. Nous utilisons ensuite une technique d’équivalence standard pour le résultat. Toutes les copies entières seront optimisées par le compilateur et min / max seront en ligne.

Notez que j’ai utilisé les lambdas de C ++ 11 pour la facilité de la frappe et que j’ai découvert depuis qu’il n’y avait pas de bonne façon de les utiliser comme comparateur pour un std::map .

 template> > struct symmesortingc_pair_sort { bool operator()( std::pair const& left, std::pair const& right ) const { if (left.second> > struct symmesortingc_pair_sort { template bool Helper( std::pair const& left, std::pair const& right ) const { std::pair left_ordered( left_reversed?left.first:left.second, left_reversed?left.second:left.first ); std::pair right_ordered( right_reversed?right.first:right.second, right_reversed?right.second:right.first ); return PairCmp()( left_ordered, right_ordered ); } bool operator()( std::pair const& left, std::pair const& right ) const { if (left.second(left, right); } else { return Helper(left, right); } } else { if (right.second(left, right); } else { return Helper(left, right); } } }; std::map, int*, symmesortingc_pair_sort > m; 

Une autre solution consiste à utiliser std::set au lieu de std::pair . Les ensembles stockent leurs données commandées, il n’est donc pas nécessaire de commander votre paire, alors répondez précisément à vos besoins.

D’autre part, les autres réponses utilisant un wrapper de comparaison autour d’une paire qui ordonne explicitement les paires pourraient être plus pratiques.