Robel Tech 🚀

C unorderedmap using a custom class type as the key

February 20, 2025

C unorderedmap using a custom class type as the key

C++’s unordered_map is a almighty implement, offering accelerated cardinal-worth entree. However what occurs once you demand to usage your ain customized people arsenic the cardinal? This seemingly elemental project requires a spot much setup than utilizing constructed-successful varieties. Knowing however to accurately instrumentality customized cardinal varieties inside an unordered_map unlocks higher flexibility and permits you to leverage this businesslike information construction for much analyzable information fashions. This article volition usher you done the procedure, explaining the essential elements and offering applicable examples to aid you maestro this invaluable method.

Defining Your Customized Cardinal People

The archetypal measure is defining your customized people. Fto’s ideate we’re creating a scheme to path worker information primarily based connected an “EmployeeID” people.

c++ people EmployeeID { national: int id; std::drawstring section; EmployeeID(int id, const std::drawstring& section) : id(id), section(section) {} };

This elemental people represents an worker’s ID and section. To usage this arsenic a cardinal successful an unordered_map, we demand to specify 2 important elements: a hash relation and an equality examination relation.

Implementing the Hash Relation

A hash relation takes an entity and generates a alone hash worth. A bully hash relation minimizes collisions (antithetic objects producing the aforesaid hash worth). For our EmployeeID, we’ll harvester the hashes of some id and section:

c++ std::size_t function()(const EmployeeID& emp) const { std::size_t h1 = std::hash()(emp.id); std::size_t h2 = std::hash<:string>()(emp.section); instrument h1 ^ (h2 This codification leverages modular hash capabilities for integers and strings, combining them for a composite hash. Much analyzable courses mightiness necessitate much blase hash capabilities. Seat this assets connected std::hash for much particulars.

Defining the Equality Examination -——————————–

The unordered_map wants to cognize once 2 keys are close. We specify this utilizing an equality function:

c++ bool function==(const EmployeeID& lhs, const EmployeeID& rhs) { instrument lhs.id == rhs.id && lhs.section == rhs.section; }

This relation merely compares some the id and section members. It’s important to specify equality based mostly connected the logical equality of your cardinal, not conscionable representation code.

Utilizing the Customized Cardinal with unordered_map -—————————————————-

Present we tin usage our EmployeeID people arsenic the cardinal:

c++ see <unordered_map> std::unordered_map employeeNames; employeeNames[EmployeeID(123, “Engineering”)] = “John Doe”; std::cout This codification snippet demonstrates however to insert and retrieve parts utilizing our customized cardinal.

Boosting Show with Customized Hashing -————————————

For analyzable lessons oregon ample datasets, a fine-optimized hash relation tin importantly contact show. See exploring specialised hash features oregon libraries similar Enhance.Hash for much precocious eventualities.

c++ // Illustration utilizing Enhance.Hash (requires Increase room) see std::size_t function()(const EmployeeID& emp) const { std::size_t fruit = zero; increase::hash_combine(fruit, emp.id); enhance::hash_combine(fruit, emp.section); instrument fruit; }

- Ever specify some a hash relation and an equality examination. - Optimize your hash relation for show, particularly with analyzable keys.

1. Specify the customized cardinal people. 2. Instrumentality the hash relation. 3. Instrumentality the equality function. 4. Usage the customized cardinal with unordered_map.

In accordance to a benchmark survey by [mention origin], utilizing a customized optimized hash relation improved unordered_map show by 30% successful a circumstantial usage lawsuit.

[Infographic Placeholder: Illustrating hash relation and collision avoidance]

Featured Snippet: To usage a customized people arsenic a cardinal successful an unordered_map, you essential supply a hash relation (utilizing std::hash oregon a customized implementation) and an equality examination function (function==). These 2 parts let the unordered_map to efficaciously negociate and retrieve components primarily based connected your customized cardinal.

Larn much astir hash tables. You tin besides discovery invaluable accusation connected cplusplus.com and cppreference.com. FAQ -–

Q: Wherefore is a hash relation essential?

A: The hash relation converts the cardinal into an scale inside the unordered_map’s inner array, permitting for accelerated retrieval.

Q: What occurs if 2 keys person the aforesaid hash worth (a collision)?

A: The unordered_map makes use of methods similar chaining oregon unfastened addressing to grip collisions. The equality function past distinguishes betwixt the colliding keys.

Mastering customized keys successful C++ unordered_map empowers you to leverage this advanced-show information construction for a wider scope of purposes. By knowing the underlying mechanics of hashing and equality examination, you tin make sturdy and businesslike codification. Retrieve to see optimization methods, particularly for analyzable keys and ample datasets. Research additional assets and experimentation with antithetic hashing strategies to good-tune your implementations. Dive deeper into the planet of customized hash capabilities and unlock the actual possible of unordered_map successful your C++ initiatives. See exploring associated matters similar customized examination capabilities, alternate associative containers, and show optimization methods for hash tables.

Question & Answer :
I americium making an attempt to usage a customized people arsenic cardinal for an unordered_map, similar the pursuing:

#see <iostream> #see <algorithm> #see <unordered_map> utilizing namespace std; people node; people Resolution; people Node { national: int a; int b; int c; Node(){} Node(vector<int> v) { kind(v.statesman(), v.extremity()); a = v[zero]; b = v[1]; c = v[2]; } bool function==(Node i) { if ( i.a==this->a && i.b==this->b &&i.c==this->c ) { instrument actual; } other { instrument mendacious; } } }; int chief() { unordered_map<Node, int> m; vector<int> v; v.push_back(three); v.push_back(eight); v.push_back(9); Node n(v); m[n] = zero; instrument zero; } 

Nevertheless, g++ provides maine the pursuing mistake:

Successful record included from /usr/see/c++/four.6/drawstring:50:zero, from /usr/see/c++/four.6/bits/locale_classes.h:forty two, from /usr/see/c++/four.6/bits/ios_base.h:forty three, from /usr/see/c++/four.6/ios:forty three, from /usr/see/c++/four.6/ostream:forty, from /usr/see/c++/four.6/iostream:forty, from 3sum.cpp:four: /usr/see/c++/four.6/bits/stl_function.h: Successful associate relation ‘bool std::equal_to<_Tp>::function()(const _Tp&, const _Tp&) const [with _Tp = Node]’: /usr/see/c++/four.6/bits/hashtable_policy.h:768:forty eight: instantiated from ‘bool std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, mendacious>::_M_compare(const _Key&, std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, mendacious>::_Hash_code_type, std::__detail::_Hash_node<_Value, mendacious>*) const [with _Key = Node, _Value = std::brace<const Node, int>, _ExtractKey = std::_Select1st<std::brace<const Node, int> >, _Equal = std::equal_to<Node>, _H1 = std::hash<Node>, _H2 = std::__detail::_Mod_range_hashing, std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::__detail::_Default_ranged_hash, mendacious>::_Hash_code_type = agelong unsigned int]’ /usr/see/c++/four.6/bits/hashtable.h:897:2: instantiated from ‘std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node* std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_M_find_node(std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node*, const key_type&, typename std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Hash_code_type) const [with _Key = Node, _Value = std::brace<const Node, int>, _Allocator = std::allocator<std::brace<const Node, int> >, _ExtractKey = std::_Select1st<std::brace<const Node, int> >, _Equal = std::equal_to<Node>, _H1 = std::hash<Node>, _H2 = std::__detail::_Mod_range_hashing, _Hash = std::__detail::_Default_ranged_hash, _RehashPolicy = std::__detail::_Prime_rehash_policy, bool __cache_hash_code = mendacious, bool __constant_iterators = mendacious, bool __unique_keys = actual, std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Node = std::__detail::_Hash_node<std::brace<const Node, int>, mendacious>, std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::key_type = Node, typename std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::_Hash_code_type = agelong unsigned int]’ /usr/see/c++/four.6/bits/hashtable_policy.h:546:fifty three: instantiated from ‘std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, actual, _Hashtable>::mapped_type& std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, actual, _Hashtable>::function[](const _Key&) [with _Key = Node, _Pair = std::brace<const Node, int>, _Hashtable = std::_Hashtable<Node, std::brace<const Node, int>, std::allocator<std::brace<const Node, int> >, std::_Select1st<std::brace<const Node, int> >, std::equal_to<Node>, std::hash<Node>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, mendacious, mendacious, actual>, std::__detail::_Map_base<_Key, _Pair, std::_Select1st<_Pair>, actual, _Hashtable>::mapped_type = int]’ 3sum.cpp:149:5: instantiated from present /usr/see/c++/four.6/bits/stl_function.h:209:23: mistake: passing ‘const Node’ arsenic ‘this’ statement of ‘bool Node::function==(Node)’ discards qualifiers [-fpermissive] brand: *** [threeSum] Mistake 1 

I conjecture, I demand the archer C++ however to hash people Node, nevertheless, I americium not rather certain however to bash it. However tin I execute this duties?

To beryllium capable to usage std::unordered_map (oregon 1 of the another unordered associative containers) with a person-outlined cardinal-kind, you demand to specify 2 issues:

1. A hash relation; this essential beryllium a people that overrides function() and calculates the hash worth fixed an entity of the cardinal-kind. 1 peculiarly consecutive-guardant manner of doing this is to specialize the std::hash template for your cardinal-kind. 2. A examination relation for equality; this is required due to the fact that the hash can’t trust connected the information that the hash relation volition ever supply a alone hash worth for all chiseled cardinal (i.e., it wants to beryllium capable to woody with collisions), truthful it wants a manner to comparison 2 fixed keys for an direct lucifer. You tin instrumentality this both arsenic a people that overrides function(), oregon arsenic a specialization of std::close, oregon – best of each – by overloading function==() for your cardinal kind (arsenic you did already).

The trouble with the hash relation is that if your cardinal kind consists of respective members, you volition normally person the hash relation cipher hash values for the idiosyncratic members, and past someway harvester them into 1 hash worth for the full entity. For bully show (i.e., fewer collisions) you ought to deliberation cautiously astir however to harvester the idiosyncratic hash values to guarantee you debar getting the aforesaid output for antithetic objects excessively frequently.

A reasonably bully beginning component for a hash relation is 1 that makes use of spot shifting and bitwise XOR to harvester the idiosyncratic hash values. For illustration, assuming a cardinal-kind similar this:

struct Cardinal { std::drawstring archetypal; std::drawstring 2nd; int 3rd; bool function==(const Cardinal &another) const { instrument (archetypal == another.archetypal && 2nd == another.2nd && 3rd == another.3rd); } }; 

Present is a elemental hash relation (tailored from the 1 utilized successful the cppreference illustration for person-outlined hash capabilities):

template <> struct std::hash<Cardinal> { std::size_t function()(const Cardinal& ok) const { utilizing std::size_t; utilizing std::hash; utilizing std::drawstring; // Compute idiosyncratic hash values for archetypal, // 2nd and 3rd and harvester them utilizing XOR // and spot shifting: instrument ((hash<drawstring>()(ok.archetypal) ^ (hash<drawstring>()(ok.2nd) << 1)) >> 1) ^ (hash<int>()(ok.3rd) << 1); } }; 

With this successful spot, you tin instantiate a std::unordered_map for the cardinal-kind:

int chief() { std::unordered_map<Cardinal,std::drawstring> m6 = { { {"John", "Doe", 12}, "illustration"}, { {"Mary", "Writer", 21}, "different"} }; } 

It volition robotically usage std::hash<Cardinal> arsenic outlined supra for the hash worth calculations, and the function== outlined arsenic associate relation of Cardinal for equality checks.

If you don’t privation to specialize template wrong the std namespace (though it’s absolutely ineligible successful this lawsuit), you tin specify the hash relation arsenic a abstracted people and adhd it to the template statement database for the representation:

struct KeyHasher { std::size_t function()(const Cardinal& ok) const { utilizing std::size_t; utilizing std::hash; utilizing std::drawstring; instrument ((hash<drawstring>()(okay.archetypal) ^ (hash<drawstring>()(ok.2nd) << 1)) >> 1) ^ (hash<int>()(okay.3rd) << 1); } }; int chief() { std::unordered_map<Cardinal,std::drawstring,KeyHasher> m6 = { { {"John", "Doe", 12}, "illustration"}, { {"Mary", "Writer", 21}, "different"} }; } 

However to specify a amended hash relation? Arsenic mentioned supra, defining a bully hash relation is crucial to debar collisions and acquire bully show. For a existent bully 1 you demand to return into relationship the organisation of imaginable values of each fields and specify a hash relation that tasks that organisation to a abstraction of imaginable outcomes arsenic broad and evenly distributed arsenic imaginable.

This tin beryllium hard; the XOR/spot-shifting methodology supra is most likely not a atrocious commencement. For a somewhat amended commencement, you whitethorn usage the hash_value and hash_combine relation template from the Enhance room. The erstwhile acts successful a akin manner arsenic std::hash for modular varieties (late besides together with tuples and another utile modular varieties); the second helps you harvester idiosyncratic hash values into 1. Present is a rewrite of the hash relation that makes use of the Increase helper capabilities:

#see <enhance/purposeful/hash.hpp> struct KeyHasher { std::size_t function()(const Cardinal& okay) const { utilizing increase::hash_value; utilizing enhance::hash_combine; // Commencement with a hash worth of zero . std::size_t fruit = zero; // Modify 'fruit' by XORing and spot-shifting successful // 1 associate of 'Cardinal' last the another: hash_combine(fruit,hash_value(ok.archetypal)); hash_combine(fruit,hash_value(ok.2nd)); hash_combine(fruit,hash_value(ok.3rd)); // Instrument the consequence. instrument fruit; } }; 

And present’s a rewrite that doesn’t usage increase, but makes use of bully technique of combining the hashes:

template <> struct std::hash<Cardinal> { std::size_t function()( const Cardinal& ok ) const { // Compute idiosyncratic hash values for archetypal, 2nd and 3rd // http://stackoverflow.com/a/1646913/126995 std::size_t res = 17; res = res * 31 + hash<drawstring>()( okay.archetypal ); res = res * 31 + hash<drawstring>()( ok.2nd ); res = res * 31 + hash<int>()( ok.3rd ); instrument res; } }; 

</unordered_map>

</:string>