Skip to content

Commit 27a91bb

Browse files
[Edit] C++: maps (#6528)
* [Edit] C++: maps * Update maps.md * fixed lint and format * Update maps.md * Update maps.md * Update maps.md ---------
1 parent 977c71b commit 27a91bb

File tree

1 file changed

+178
-75
lines changed

1 file changed

+178
-75
lines changed

Diff for: content/cpp/concepts/maps/maps.md

+178-75
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,250 @@
11
---
2-
Title: 'Maps'
3-
Description: 'Maps are associative containers that have elements with key-value pairs.'
2+
Title: 'Map'
3+
Description: 'An associative container that stores unique key-value pairs sorted by key.'
44
Subjects:
55
- 'Computer Science'
6-
- 'Game Development'
6+
- 'Web Development'
77
Tags:
8-
- 'Objects'
8+
- 'Collections'
9+
- 'Data Structures'
10+
- 'Maps'
911
- 'OOP'
10-
- 'Classes'
1112
CatalogContent:
1213
- 'learn-c-plus-plus'
1314
- 'paths/computer-science'
1415
---
1516

16-
**Maps** are associative containers that have elements with key-value pairs. The keys are used to sort and identify the elements, while the values store the content associated with the keys. Each mapped value must have a unique key value.
17+
A **`map`** is an associative container in C++ that stores key-value pairs in sorted order. Each key is unique and maps to a single value, enabling efficient data storage and retrieval based on keys. C++ maps use a self-balancing [binary search tree](https://www.codecademy.com/resources/docs/general/binary-search-tree), typically a red-black tree, to achieve logarithmic time complexity for common operations.
18+
19+
Maps support efficient lookup, insertion, and deletion based on unique keys. They suit use cases such as dictionaries, phone books, configuration settings, and any situation that requires associating values with unique identifiers. Unlike [unordered maps](https://www.codecademy.com/resources/docs/cpp/unordered-map), standard maps maintain their elements in sorted order by key, which is beneficial for range-based operations.
1720

1821
## Syntax
1922

20-
An empty map can be created by using the map keyword, declaring the data types of the key and value, and setting a `mapName`:
23+
To use maps in C++, include the `<map>` header file:
2124

2225
```pseudo
23-
std::map<type1, type2> mapName;
26+
#include <map>
27+
28+
// General syntax for creating a map
29+
std::map<KeyType, ValueType> mapName;
2430
```
2531

26-
`type1` and `type2` are the data types of the key and value, respectively.
32+
**Parameters:**
2733

28-
To set a list at declaration, the following syntax is used:
34+
- `KeyType`: The type of the keys in the map. Common key types include `int`, `string`, or custom classes that have the less-than operator defined.
35+
- `ValueType`: The type of the mapped values. This can be any valid C++ type, including built-in types, STL containers, or user-defined classes.
36+
- `mapName`: The identifier for the map instance.
2937

30-
```pseudo
31-
std::map<type1, type2> mapName { {key1, value1}, {key2, value2}, ...};
32-
```
38+
**Return value:**
3339

34-
Each `value` must have a unique `key` assigned to it.
40+
Maps return various iterators and containers based on the operation performed. For example, [`.find()`](https://www.codecademy.com/resources/docs/cpp/maps/find) returns an iterator to the element if found, or to [`.end()`](https://www.codecademy.com/resources/docs/cpp/maps/end) if not found.
3541

36-
## Example
42+
## Example 1: Creating and Initializing a Map
3743

38-
The following example creates an empty map, `emptyMap`, and a map set with values, `clothingStore`:
44+
This example demonstrates how to create and initialize a map that associates names with ages:
3945

4046
```cpp
4147
#include <iostream>
42-
#include <iterator>
4348
#include <map>
49+
#include <string>
4450

4551
int main() {
46-
// Initializing empty map
47-
std::map<std::string, int> emptyMap;
52+
// Create a map with string keys and integer values
53+
std::map<std::string, int> ages;
54+
55+
// Insert key-value pairs using different methods
56+
// Using operator[]
57+
ages["Alice"] = 30;
58+
// Using insert with pair
59+
ages.insert(std::pair<std::string, int>("Bob", 25));
60+
// Using insert with initializer list
61+
ages.insert({"Charlie", 35});
62+
63+
// Print the map contents
64+
std::cout << "Map contents:" << std::endl;
65+
for (const auto& pair : ages) {
66+
std::cout << pair.first << ": " << pair.second << std::endl;
67+
}
4868

49-
// Initializing map with items
50-
std::map<std::string, int> clothingStore {{"tshirt", 10}, {"pants", 12}, {"sweaters", 18}};
69+
// Check the size of the map
70+
std::cout << "Map size: " << ages.size() << std::endl;
71+
72+
return 0;
5173
}
5274
```
5375

54-
## Accessing Elements
76+
This code creates a map that associates `names` (strings) with `ages` (integers). It demonstrates three different ways to insert elements into a map: using the subscript operator `[]`, using the [`.insert()`](https://www.codecademy.com/resources/docs/cpp/maps/insert) method with a `pair`, and using `.insert()` with an initializer list.
5577

56-
Elements can be accessed within a map using the following square bracket syntax:
78+
The output produced by this code will be:
5779

58-
```pseudo
59-
mapName[key]
80+
```shell
81+
Map contents:
82+
Alice: 30
83+
Bob: 25
84+
Charlie: 35
85+
Map size: 3
6086
```
6187

62-
This returns the mapped value associated with the `key`.
88+
Notice that the elements are automatically sorted by key (alphabetically in this case).
6389

64-
### Example
90+
## Example 2: Accessing Elements from a Map
6591

66-
The `sweaters` element is retrieved from the `clothingStore` map initialized in the previous example:
67-
68-
```cpp
69-
std::cout << clothingStore["sweaters"]; // Output: 18
70-
```
71-
72-
## Comparison Function
73-
74-
By default, elements are sorted by their key in ascending order.
92+
This example shows different ways to access elements in a map, including checking if a key exists.
7593

7694
```cpp
7795
#include <iostream>
78-
#include <iterator>
7996
#include <map>
97+
#include <string>
8098

8199
int main() {
82-
// Initializing map with items
83-
std::map<int, std::string> reptiles {
84-
{10, "Komodo Dragon"}, {15, "Saltwater Crocodile"}, {8, "Leatherback Sea Turtle"}
100+
// Create a map of country codes to country names
101+
std::map<std::string, std::string> countries = {
102+
{"US", "United States"},
103+
{"CA", "Canada"},
104+
{"UK", "United Kingdom"},
105+
{"FR", "France"},
106+
{"JP", "Japan"}
85107
};
86108

109+
// Access using operator[] - simple but no error checking
110+
std::cout << "US is for " << countries["US"] << std::endl;
87111

88-
// Initializing iterator
89-
std::map<int, std::string> :: iterator iter;
90-
91-
for (iter = reptiles.begin(); iter != reptiles.end(); ++iter) {
92-
std::cout << '\t' << iter->first << '\t' << iter->second
93-
<< '\n';
112+
// Access using at() - throws exception if key doesn't exist
113+
try {
114+
std::cout << "CA is for " << countries.at("CA") << std::endl;
115+
std::cout << "DE is for " << countries.at("DE") << std::endl; // Will throw exception
116+
} catch (const std::out_of_range& e) {
117+
std::cout << "Exception: " << e.what() << std::endl;
94118
}
95-
}
96-
```
97119

98-
The snippet above outputs the following:
120+
// Access using find() - safer way to check if key exists
121+
auto it = countries.find("UK");
122+
if (it != countries.end()) {
123+
std::cout << "Found: " << it->first << " is for " << it->second << std::endl;
124+
} else {
125+
std::cout << "Key not found!" << std::endl;
126+
}
99127

100-
```shell
101-
8 Leatherback Sea Turtle
102-
10 Komodo Dragon
103-
15 Saltwater Crocodile
104-
```
128+
// Check if a key exists before accessing
129+
if (countries.count("FR") > 0) {
130+
std::cout << "France exists in the map" << std::endl;
131+
}
105132

106-
The default comparison function can be changed to `std::greater<dataType>` in order to sort the elements in descending order.
133+
// Using operator[] will create an entry if it doesn't exist
134+
std::cout << "ZZ is " << countries["ZZ"] << std::endl; // Creates entry with empty string
135+
std::cout << "Map size after accessing non-existent key: " << countries.size() << std::endl;
107136

108-
### Syntax
137+
return 0;
138+
}
139+
```
109140

110-
To set the comparison function while initializing an empty map:
141+
The output generated by this code will be:
111142

112-
```pseudo
113-
std::map<type1, type2, std::greater<dataType>> mapName;
143+
```shell
144+
US is for United States
145+
CA is for Canada
146+
DE is for Exception: map::at
147+
Found: UK is for United Kingdom
148+
France exists in the map
149+
ZZ is
150+
Map size after accessing non-existent key: 6
114151
```
115152

116-
To set the comparison function while initializing a map with items:
153+
This example demonstrates four different ways to access elements in a map:
117154

118-
```pseudo
119-
std::map<type1, type2, std::greater<dataType>> mapName { {key1, value1}, {key2, value2}, ...};
120-
```
155+
1. Using the subscript operator `[]` - simple but creates a new element if the key doesn't exist.
156+
2. Using the `.at()` method - throws an exception if the key isn't found.
157+
3. Using the `.find()` method - returns an iterator that you can check.
158+
4. Using the [`.count()`](https://www.codecademy.com/resources/docs/cpp/maps/count) method - checks if a key exists without modifying the map.
121159

122-
The `dataType` for the comparison function above must be the same as `type1` which is the data type for the keys.
160+
Note how using the `[]` operator with a non-existent key "ZZ" created a new entry with an empty string value, increasing the map's size.
123161

124-
### Codebyte Example
162+
## Codebyte Example: Adding and Modifying Elements in a Map
125163

126-
Setting the previous example's comparison function to `std::greater<int>`:
164+
This example shows how to add new elements and modify existing ones in a map:
127165

128166
```codebyte/cpp
129167
#include <iostream>
130-
#include <iterator>
131168
#include <map>
169+
#include <string>
132170
133171
int main() {
134-
// Initializing map with items
135-
std::map<int, std::string, std::greater<int>> reptiles {
136-
{10, "Komodo Dragon"}, {15, "Saltwater Crocodile"}, {8, "Leatherback Sea Turtle"}
137-
};
172+
// Create a map to store student grades
173+
std::map<std::string, char> grades;
174+
175+
// Add elements
176+
grades["John"] = 'B';
177+
grades["Mary"] = 'A';
178+
grades["Steve"] = 'C';
138179
180+
std::cout << "Initial grades:" << std::endl;
181+
for (const auto& pair : grades) {
182+
std::cout << pair.first << ": " << pair.second << std::endl;
183+
}
184+
185+
// Modify existing elements
186+
grades["John"] = 'A'; // John's grade improved
139187
140-
// Initializing iterator
141-
std::map<int, std::string> :: iterator iter;
188+
// Add new elements with insert()
189+
// insert() returns a pair: iterator to element and bool indicating success
190+
auto result = grades.insert({"Lisa", 'B'});
191+
if (result.second) {
192+
std::cout << "\nSuccessfully added " << result.first->first << std::endl;
193+
}
142194
143-
for (iter = reptiles.begin(); iter != reptiles.end(); ++iter) {
144-
std::cout << '\t' << iter->first << '\t' << iter->second << '\n';
195+
// insert() won't replace existing elements
196+
auto result2 = grades.insert({"Mary", 'C'});
197+
if (!result2.second) {
198+
std::cout << "Couldn't replace Mary's grade using insert()" << std::endl;
145199
}
200+
201+
// Use emplace() to construct element in-place
202+
grades.emplace("David", 'B');
203+
204+
// Update an existing element using at()
205+
grades.at("Steve") = 'B'; // Steve's grade improved
206+
207+
std::cout << "\nFinal grades:" << std::endl;
208+
for (const auto& pair : grades) {
209+
std::cout << pair.first << ": " << pair.second << std::endl;
210+
}
211+
212+
return 0;
146213
}
147214
```
215+
216+
This example demonstrates various ways to add and modify elements in a map:
217+
218+
1. Using the `[]` operator to add new elements or modify existing ones.
219+
2. Using the `.insert()` method which only adds elements if the key doesn't already exist.
220+
3. Using the [`.emplace()`](https://www.codecademy.com/resources/docs/cpp/maps/emplace) method to construct elements in-place.
221+
4. Using the `.at()` method to modify existing elements with bounds checking.
222+
223+
Note that the elements are always sorted by key (alphabetically in this case).
224+
225+
## Frequently Asked Questions
226+
227+
<details>
228+
<summary>1. What is the difference between a map and an unordered map in C++?</summary>
229+
<p>A map keeps its elements sorted by key and is typically implemented as a balanced binary search tree, providing logarithmic time complexity for operations. An unordered map uses a hash table implementation, offering constant time complexity on average but without ordering guarantees.</p>
230+
</details>
231+
232+
<details>
233+
<summary>2. Can I use custom objects as keys in a map?</summary>
234+
<p>Yes, but you must provide a comparison operator (`operator<`) for the key type or specify a custom comparator when declaring the map. The comparator must establish a strict weak ordering.</p>
235+
</details>
236+
237+
<details>
238+
<summary>3. How do I iterate through all elements in a map?</summary>
239+
<p>You can use a range-based for loop: `for (const auto& pair : myMap) {...}` or traditional iterators: `for (auto it = myMap.begin(); it != myMap.end(); ++it) {...}`.</p>
240+
</details>
241+
242+
<details>
243+
<summary>4. What happens if I use the subscript operator `[]` with a key that doesn't exist in the map?</summary>
244+
<p>A new element with that key will be inserted into the map with a value-initialized value (e.g., 0 for integers, empty string for std::string).</p>
245+
</details>
246+
247+
<details>
248+
<summary>5. How can I check if a key exists in a map without adding it?</summary>
249+
<p>Use the `find()` method or the `count()` method, both of which don't modify the map. Don't use the `[]` operator for checking existence.</p>
250+
</details>

0 commit comments

Comments
 (0)