Sparse array example: (why hold space for thousands of elements when all we have is five)
#include <string.h> #include <iostream> #include <map> #include <utility> using namespace std; int main() { map<int, string> Employees; // 1) Assignment using array index notation Employees[5234] = "Mike C."; Employees[3374] = "Charlie M."; Employees[1923] = "David D."; Employees[7582] = "John A."; Employees[5328] = "Peter Q."; cout << "Employees[3374]=" << Employees[3374] << endl << endl; cout << "Map size: " << Employees.size() << endl; cout << endl << "Natural Order:" << endl; for( map<int,string>::iterator ii=Employees.begin(); ii!=Employees.end(); ++ii) { cout << (*ii).first << ": " << (*ii).second << endl; } cout << endl << "Reverse Order:" << endl; for( map<int,string>::reverse_iterator ii=Employees.rbegin(); ii!=Employees.rend(); ++ii) { cout << (*ii).first << ": " << (*ii).second << endl; } }
Compile: g++ testMap.cpp
Run: ./a.out
Employees[3374]=Charlie M. Map size: 5 Natural Order: 1923: David D. 3374: Charlie M. 5234: Mike C. 5328: Peter Q. 7582: John A. Reverse Order: 7582: John A. 5328: Peter Q. 5234: Mike C. 3374: Charlie M. 1923: David D.
Example using a "string" as an array index:
#include <string.h> #include <iostream> #include <map> #include <utility> using namespace std; int main() { map<string, int> Employees; // Examples of assigning Map container contents // 1) Assignment using array index notation Employees["Mike C."] = 5234; Employees["Charlie M."] = 3374; // 2) Assignment using member function insert() and STL pair Employees.insert(std::pair<string,int>("David D.",1923)); // 3) Assignment using member function insert() and "value_type()" Employees.insert(map<string,int>::value_type("John A.",7582)); // 4) Assignment using member function insert() and "make_pair()" Employees.insert(std::make_pair("Peter Q.",5328)); cout << "Map size: " << Employees.size() << endl; for( map<string, int>::iterator ii=Employees.begin(); ii!=Employees.end(); ++ii) { cout << (*ii).first << ": " << (*ii).second << endl; } }
Compile: g++ testMap.cpp
Run: ./a.out
Map size: 5 Charlie M.: 3374 David D.: 1923 John A.: 7582 Mike C.: 5234 Peter Q.: 5328
Note: The fully defined STL map defines a comparison operator in the map declaration so that the indexes can be ordered. This is used to provide a default comparison operator for the data type. In the above example, the key type is an integer and the C++ "equals" (=) and "less than" operator (<) can operate on an integer so the example works. The use of the STL algorithm std::less<> can be specified explicitly as in the following declaration:
std::map<int, string, std::less< int > >
If defining your own class as the index (first value), C++ will not know how to perform the comparison, thus you will have to provide an operator to perform this function.
The first element in a map can be a class or even another STL container such as a pair. If using a class, the class must provide an overloaded "equals" (=) and "less than" operator (<).
Thus using "char" instead of "string" requires the use of a comparison function:#include <string.h> #include <iostream> #include <map> #include <utility> using namespace std; struct cmp_str { bool operator()(char const *a, char const *b) { return std::strcmp(a, b) < 0; } }; int main() { map<char *, int, cmp_str> Employees; // Examples of assigning Map container contents // 1) Assignment using array index notation Employees["Mike C."] = 5234; Employees["Charlie M."] = 3374; // 2) Assignment using member function insert() and STL pair Employees.insert(std::pair<char *,int>("David D.",1923)); // 3) Assignment using member function insert() and "value_type()" Employees.insert(map<char *,int>::value_type("John A.",7582)); // 4) Assignment using member function insert() and "make_pair()" Employees.insert(std::make_pair((char *)"Peter Q.",5328)); cout << "Map size: " << Employees.size() << endl; for( map<char *, int, cmp_str>::iterator ii=Employees.begin(); ii!=Employees.end(); ++ii) { cout << (*ii).first << ": " << (*ii).second << endl; } }
Compile: g++ testMap.cpp
Run: ./a.out
Map size: 5 Charlie M.: 3374 David D.: 1923 John A.: 7582 Mike C.: 5234 Peter Q.: 5328
SGI Map Documentation:
Using STL MAP to store class objects:
This example uses a string as the MAP index and an object as the value pair. In order for a class to be stored in an STL container, it must have a default constructor, the class must be assignable, less than comparable and equality comparable. Thus the overloaded = and < operators are provided to satisfy MAP container use.
#include <iostream> #include <map> using namespace std; class AAA { friend ostream &operator<<(ostream &, const AAA &); public: int x; int y; float z; AAA(); AAA(const AAA &); ~AAA(){}; AAA &operator=(const AAA &rhs); int operator==(const AAA &rhs) const; int operator<(const AAA &rhs) const; }; AAA::AAA() // Constructor { x = 0; y = 0; z = 0; } AAA::AAA(const AAA ©in) // Copy constructor to handle pass by value. { x = copyin.x; y = copyin.y; z = copyin.z; } ostream &operator<<(ostream &output, const AAA &aaa) { output << aaa.x << ' ' << aaa.y << ' ' << aaa.z << endl; return output; } AAA& AAA::operator=(const AAA &rhs) { this->x = rhs.x; this->y = rhs.y; this->z = rhs.z; return *this; } int AAA::operator==(const AAA &rhs) const { if( this->x != rhs.x) return 0; if( this->y != rhs.y) return 0; if( this->z != rhs.z) return 0; return 1; } int AAA::operator<(const AAA &rhs) const { if( this->x == rhs.x && this->y == rhs.y && this->z < rhs.z) return 1; if( this->x == rhs.x && this->y < rhs.y) return 1; if( this->x < rhs.x ) return 1; return 0; } main() { map<string, AAA> M; AAA Ablob ; Ablob.x=7; Ablob.y=2; Ablob.z=4.2355; M["C"] = Ablob; Ablob.x=5; M["B"] = Ablob; Ablob.z=3.2355; M["A"] = Ablob; Ablob.x=3; Ablob.y=7; Ablob.z=7.2355; M["D"] = Ablob; for( map<string, AAA>::iterator ii=M.begin(); ii!=M.end(); ++ii) { cout << (*ii).first << ": " << (*ii).second << endl; } return 0; }
Compile: g++ testMap.cpp
Run: ./a.out
Output:
A: 5 2 3.2355 B: 5 2 4.2355 C: 7 2 4.2355 D: 3 7 7.2355
Note: The Map elements were inserted out of order but put in order in the internal Map structure and thus printed out in order. This is why the overloaded "<" operator was required. An alternative friend class with an overloaded "()" operator is shown in the next example.
[Potential Pitfall]: The following error occurs when the < operator is omitted from the class AAA.
/tmp/cca5a9G9.o: In function `main':testMap.cpp:(.text+0x3c6): undefined reference to `operator<<(std::basic_ostream<char, std::char_traits<char> >&, AAA const&)'
collect2: ld returned 1 exit status
[Potential Pitfall]: The following error occurs when the = operator is omitted from the class AAA.
/tmp/cciGBZgS.o: In function `main': testMap.cpp:(.text+0x263): undefined reference to `AAA::operator=(AAA const&)' testMap.cpp:(.text+0x2c8): undefined reference to `AAA::operator=(AAA const&)' testMap.cpp:(.text+0x32e): undefined reference to `AAA::operator=(AAA const&)' testMap.cpp:(.text+0x3a2): undefined reference to `AAA::operator=(AAA const&)' collect2: ld returned 1 exit status
Using class objects as a Map key:
#include <iostream> #include <string> #include <map> using namespace std; class Person { friend class PersonLessThan; public: string firstName; string lastName; Person(const string &firstName, const string &lastName); }; Person::Person(const string &_firstName, const string &_lastName) : firstName(_firstName), lastName(_lastName) {} class PersonLessThan { public: bool operator( )(const Person& p1, const Person& p2) const { if (p1.lastName < p2.lastName) return(true); else if (p1.lastName == p2.lastName) return(p1.firstName < p2.firstName); else return(false); } }; main() { map<Person, bool, PersonLessThan> M; Person p_1("Wilma","Flintstone"); Person p_2("Betty","Rubble"); Person p_3("Fred","Flintstone"); Person p_4("Barney","Rubble"); M[p_1] = true; M[p_2] = true; M[p_3] = true; M[p_4] = true; for( map<Person, bool>::iterator ii=M.begin(); ii!=M.end(); ++ii) { cout << ((*ii).first).lastName << ", " << ((*ii).first).firstName << ": " << (*ii).second << endl; } }
Run: ./examplePersonKey
Flintstone, Fred: 1 Flintstone, Wilma: 1 Rubble, Barney: 1 Rubble, Betty: 1The people are written out in sorted order as defined by the class PersonLessThan operator "()". The underlying Map structure requires a sort method so that it can insert the object into the underlying structure. You have two choices:
- Map definition: map<key, value> M;
Sort defined as a key class overloaded operator "<"
Shown in previous example. - Map definition: map<key, value, CompareClass> M;
Sort defined as a key class friend class with an overloaded "()" operator.
Shown in this example.
Constructor/Declaration:
Method/operator | Description |
---|---|
map<K,T> m; | Map declaration of key of type "K" and value of type "T". Allocate an empty map: map<int,int> m = new map<int,int>(); |
map<K,T,compare> m; | Map declaration of key of type "K" and value of type "T". A class (or struct) with an overloaded "()" operator function to compare keys so that they can be ordered in the underlying tree storage structure. Allocate an empty map: map<int,float,CFnCompare> m = new map<int,float,CFnCompare>(); Where CFnCompare is a class which defines the overloaded operator "()" which can compare the key type (in this case int) |
Size methods/operators:
Method/operator | Description |
---|---|
empty() | Returns bool (true/false). True if empty. Declaration: bool empty() const |
size() | Number of elements of the map. Declaration: size_type size() const |
max_size() | Number of elements of the map. Declaration: size_type max_size() const |
Other methods/operators:
Method/operator | Description |
---|---|
erase(&key) erase(iterator) erase( iterator first, iterator last ) |
Erase element of the Map identified by key, at element pos or elements in a range Declaration (all C++): size_type erase( const key_type& key ) Declaration (until c++11):
|
clear() | Remove all elements of the entire Map Declaration: void clear() |
= | Assign/copy entire contents of one Map to another Declaration: map& operator=( const map& other ) C++11 introduces additional prototypes which use allocators |
== != < <= > >= |
C++ operators available to compare Map elements |
[key] | Access the contents of one Map element indicated by its key Declaration: T& operator[]( const Key& key ) |
at(key) | Access the contents of one Map element indicated by its key Declaration: const T& at( const Key& key ) const; Introduced in C++11 |
insert(std::pair) | Insert one Map element with the specified key/value pair. Declaration: std::pair<iterator,bool> insert( const std::pair<key,value> ); |
swap(&other) | Swap one Map with another. This Map class member function should not be confused with std::swap(std::map) Declaration: void swap( map& other ) |
find(&key) | Finds the Map iterator for the specified key. Declaration: iterator find( const Key& key ) This function bridges the key/index vs iterator methodologies. |
Iterator methods/operators:
Method/operator | Description |
---|---|
begin() | Return iterator to first element of the map. Declaration: const_iterator begin() const |
end() | Return iterator to element after the last element of the map. No element exists in this location and attempting to access is undefined behavior Declaration: const_iterator end() const |
rbegin() | Return iterator to first element of the map (reverse order). This is equivalent to the last element of the non-reversed container. Declaration: const_reverse_iterator rbegin() const |
rend() | Return iterator to end of the map (not last element but past last element) (reverse order). This is equivalent to the element preceding the first element of the non-reversed container. Note that this is a placeholder and that no element exists in this location and attempting to access is undefined behavior Declaration: const_reverse_iterator rend() const |
The STL multipmap allows duplicate keys.
#include <string.h> #include <iostream> #include <map> #include <utility> using namespace std; int main() { // Compare (<) function not required since it is built into string class. // else declaration would comparison function in multimap definition. // i.e. multimap<string, int, compare> m; multimap<string, int> m; m.insert(pair<string, int>("a", 1)); m.insert(pair<string, int>("c", 2)); m.insert(pair<string, int>("b", 3)); m.insert(pair<string, int>("b", 4)); m.insert(pair<string, int>("a", 5)); m.insert(pair<string, int>("b", 6)); cout << "Number of elements with key a: " << m.count("a") << endl; cout << "Number of elements with key b: " << m.count("b") << endl; cout << "Number of elements with key c: " << m.count("c") << endl; cout << "Elements in m: " << endl; for (multimap<string, int>::iterator it = m.begin(); it != m.end(); ++it) { cout << " [" << (*it).first << ", " << (*it).second << "]" << endl; } pair<multimap<string, int>::iterator, multimap<string, int>::iterator> ppp; // equal_range(b) returns pair<iterator,iterator> representing the range // of element with key b ppp = m.equal_range("b"); // Loop through range of maps of key "b" cout << endl << "Range of \"b\" elements:" << endl; for (multimap<string, int>::iterator it2 = ppp.first; it2 != ppp.second; ++it2) { cout << " [" << (*it2).first << ", " << (*it2).second << "]" << endl; } // Can't do this (??) // cout << ppp.first << endl; // cout << ppp.second << endl; m.clear(); }
Compile: g++ testMultimap.cpp
Run: ./a.out
Number of elements with key a: 2
Number of elements with key b: 3
Number of elements with key c: 1
Elements in m:
[a, 1]
[a, 5]
[b, 3]
[b, 4]
[b, 6]
[c, 2]
Range of "b" elements:
[b, 3]
[b, 4]
[b, 6]
SGI STL Documentation: