
上QQ阅读APP看书,第一时间看更新
How to do it...
In this section, we will implement an application that creates a map from a list of billionaires. The map maps from each country to a reference to the wealthiest person in that country and a counter that tells how many billionaires that country has.
- As always, we need to include some headers first and we declare that we use namespace std by default.
#include <iostream>
#include <functional>
#include <list>
#include <map>
using namespace std;
- Let's define a structure that represents billionaire items for our list.
struct billionaire {
string name;
double dollars;
string country;
};
- In the main function, we first define the list of billionaires. There are many billionaires in the world, so let's construct a limited list with just some of the richest persons in some countries. This list is already ordered. The rankings are actually taken from the Forbes 2017 list The World's Billionaires at https://www.forbes.com/billionaires/list/:
int main()
{
list<billionaire> billionaires {
{"Bill Gates", 86.0, "USA"},
{"Warren Buffet", 75.6, "USA"},
{"Jeff Bezos", 72.8, "USA"},
{"Amancio Ortega", 71.3, "Spain"},
{"Mark Zuckerberg", 56.0, "USA"},
{"Carlos Slim", 54.5, "Mexico"},
// ...
{"Bernard Arnault", 41.5, "France"},
// ...
{"Liliane Bettencourt", 39.5, "France"},
// ...
{"Wang Jianlin", 31.3, "China"},
{"Li Ka-shing", 31.2, "Hong Kong"}
// ...
};
- Now, let's define the map. It maps from the country string to a pair. The pair contains a (const) copy of the first billionaire of every country from our list. That is automatically the richest billionaire per country. The other variable in the pair is a counter, which we will increment for every following billionaire in that country.
map<string, pair<const billionaire, size_t>> m;
- Now, let's go through the list and try to emplace a new payload pair for every country. The pair contains a reference to the billionaire we are currently looking at and a counter value of 1.
for (const auto &b : billionaires) {
auto [iterator, success] = m.try_emplace(b.country, b, 1);
- If that step was successful, then we don't need to do anything else. The pair for which we provided the constructor arguments b, 1 has been constructed and inserted into the map. If the insertion was not successful because the country key exists already, then the pair was not constructed. If our billionaire structure was very large, this would have saved us the runtime cost of copying it.
However, in the nonsuccessful case, we still need to increment the counter for this country.
if (!success) {
iterator->second.second += 1;
}
}
- Ok, that's it. We can now print how many billionaires there are per country, and who is the wealthiest one in each country.
for (const auto & [key, value] : m) {
const auto &[b, count] = value;
cout << b.country << " : " << count
<< " billionaires. Richest is "
<< b.name << " with " << b.dollars
<< " B$\n";
}
}
- Compiling and running the program yields the following output. (Of course, the output is limited, because we limited our input map.)
$ ./efficient_insert_or_modify
China : 1 billionaires. Richest is Wang Jianlin with 31.3 B$
France : 2 billionaires. Richest is Bernard Arnault with 41.5 B$
Hong Kong : 1 billionaires. Richest is Li Ka-shing with 31.2 B$
Mexico : 1 billionaires. Richest is Carlos Slim with 54.5 B$
Spain : 1 billionaires. Richest is Amancio Ortega with 71.3 B$
USA : 4 billionaires. Richest is Bill Gates with 86 B$