Exercise 11.1

1
2
3
// element of map type is key-value pair, in another word, value is associated with keyword and could be accessed through keyword, like map[keyword].
// element of vector contains one individual object, compared with map, could also access the element through style like vector[index], while index is an integer.

Exercise 11.2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int main()
{
  // list: insert an element into a position which is not head or back.
  list<int> li = {1, 2, 3, 4, 5, 6, 7, 8};
  li.insert(++li.begin(), 3);
  cout << "\nlist" << endl;
  for(const auto &i : li) cout << i << endl;
  // vector: random access
  vector<int> vi(li.cbegin(), li.cend());
  cout << "\nvector" << endl;
  cout << vi[4] << endl;
  // deque, insert or remove elements at head or back
  deque<int> di(li.cbegin(), li.cend());
  di.push_back(9);
  cout << "\ndeque" << endl;
  for(const auto &i : di) cout << i << endl;
  // map, associated key-value pair
  map<string, int> alphabegical;
  alphabegical["a"] = 1;
  alphabegical["b"] = 2;
  cout << "\nmap" << endl;
  for(const auto &w : alphabegical)
    cout << w.first << " " << w.second << endl;
  // set, filter keywords
  set<string> ss = {"fuck", "shit", "asshole", "bullshit"};
  cout << "\nset" << endl;
  for(const auto &s : ss) cout << s << endl;
}

Exercise 11.3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int main()
{
  map<string, size_t> word_cound;
  set<string> exclude = {"The", "But", "And", "Or", "An", "A",
		       "the", "but", "and", "or", "an", "a"};
  string word;
  while(cin >> word)
    if(exclude.find(word) == exclude.end())
      ++word_cound[word];
  for(const auto &w : word_cound)
    cout << w.first << " occurs " << w.second
       << ((w.second > 1) ? " times" : " time") << endl;
}

Exercise 11.4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
  map<string, size_t> word_cound;
  set<string> exclude = {"The", "But", "And", "Or", "An", "A",
		       "the", "but", "and", "or", "an", "a"};
  string word;
  while(cin >> word)
    if(exclude.find(word) == exclude.end())
      {
      auto first = word.begin();
      auto last = word.end();
      while(first != last)
	{
	  if(isupper(*first))
	    *first = tolower(*first);
	  ++first;
	}
      if(ispunct(*(--last))) word.pop_back();
      ++word_cound[word];
      }
  for(const auto &w : word_cound)
    cout << w.first << " occurs " << w.second
       << ((w.second > 1) ? " times" : " time") << endl;
}

Exercise 11.5

1
2
3
4
5
// map<keyword_type, value_type>
// set<keyword_type>
// When there is a need to use key-value pair, map is preferred,
// else if a collection of keywords is desired, set is enough.

Exercise 11.6

1
2
3
4
5
// set: unique elements
// list: not unique elements
// When there is a need for a unique collection of keywords, set is preferred,
// else list is better.

Exercise 11.7

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int main()
{
  map<string, vector<string>> family;
  family["Johnson"] = vector<string>{"Tom", "jack", "Lily"};
  family["Johnson"].push_back("Joe");
  for(const auto &p : family)
    {
      cout << "Family " << p.first
	 << " Children's names " << endl;
      for(const auto &s : p.second) cout << s << " ";
      cout << endl;
    }
}

Exercise 11.8

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
int main()
{
  string word;
  vector<string> words;
  while(cin >> word)
    {
      auto iter = find(words.begin(), words.end(), word);
      if(iter == words.end())
      words.push_back(word);
    }
  cout << "Unique words among inputs: " << endl;
  for(const auto &s : words) cout << s << endl;
}
// if using type set, program would be much easier, the type itself determines that there is no duplicated elements within, so just push word to set and omit checkwork would do the job for us.

Exercise 11.9

1
2
map<string, list<int>> word_line_number;

Exercise 11.10

1
2
3
// map<vector<int>::iterator, int> is ok, for that vector<int>::iterator supports relationship operators like <, <=;
// while map<list<int>::iterator, int> is impossible, for that list<int>::iterator just supports relationship operators of == and !=.

Exercise 11.11

1
2
3
4
5
6
7
8
9
bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
  return lhs.isbn()f < rhs.isbn();
}
int main()
{
  multiset<Sales_data, bool (*)(const Sales_data &, const Sales_data &)> bookstore(compareIsbn);
}

Exercise 11.12

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
int main()
{
  vector<string> vs = {"hello", "world"};
  vector<int> vi = {1, 2};
  pair<string, int> p;
  vector<pair<string, int>> vp;
  auto vs_begin = vs.cbegin();
  auto vi_begin = vi.cbegin();
  while(vs_begin != vs.end() && vi_begin != vi.end())
    {
      p.first = *vs_begin;
      p.second = *vi_begin;
      vp.push_back(p);
      ++vs_begin;
      ++vi_begin;
    }
  for(const auto &p : vp)
    cout << "First " << p.first << " second " << p.second << endl;
}

Exercise 11.13

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
  vector<string> vs = {"hello", "world"};
  vector<int> vi = {1, 2};
  vector<pair<string, int>> vp;
  pair<string, int> p;
  auto vs_begin = vs.cbegin();
  auto vi_begin = vi.cbegin();
  while(vs_begin != vs.end() && vi_begin != vi.end())
    {
      // first way is illustrated in 11.12.cpp
      // second way
      // p = make_pair(*vs_begin, *vi_begin);
      // third way
      // p = {*vs_begin, *vi_begin};
      // fourth way: best
      // easier to write and understand
      vp.emplace_back(*vs_begin, *vi_begin);
      // vp.push_back(p);
      ++vs_begin;
      ++vi_begin;
    }
  for(const auto &p : vp)
    cout << "First " << p.first << " second " << p.second << endl;
}

Exercise 11.14

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
int main()
{
  map<string, vector<pair<string, unsigned>>> family;
  family["Johnson"] = vector<pair<string, unsigned>>
    {{"Tom", 19990712},
     {"jack", 20040918},
     {"Lily", 20061123}};
  family["Johnson"].emplace_back("Joe", 20100830);
  for(const auto &p : family)
    {
      cout << "Family " << p.first
	 << " Children's names " << endl;
      for(const auto &p2 : p.second)
      cout << p2.first << " birthday " << p2.second << endl;
    }
}

Exercise 11.15

1
2
3
4
5
// map<int, vector<int>>
// mapped_type: vector<int>
// key_type: int
// value_type: pair<const int, vector<int>>

Exercise 11.16

1
2
3
4
5
6
7
8
9
int main()
{
  map<int, int> sample = {{1, 2}};
  auto beg = sample.begin();
  cout << beg->first << " " << beg->second << endl;
  beg->second = 3;
  cout << beg->first << " " << beg->second << endl;
}

Exercise 11.17

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// c: multiset<string>
// v: vector<string>
// copy(v.begin(), v.end(), inserter(c, c.end()))
// copy elements of v to c, with same order
// copy(v.begin(), v.end(), back_inserter(c))
// illegal, multiset does not support push_back
// copy(c.begin(), c.end(), inserter(v. v.end()))
// copy elements of c to v, with same order
// copy(c.begin(), c.end(), back_inserter(v))
// copy elements of c to v, with same order

Exercise 11.18

1
2
3
// P382 type of map_it
// map<string, size_t>::const_iterator

Exercise 11.19

1
2
3
// multiset<Sales_data, decltype(comapreIsbn)*> bookstore(compareIsbn);
// multiset<Sales_data, bool (*)(const Sales_data &, const Sales_data &)>::iterator iter = bookstore.begin();

Exercise 11.20

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int main()
{
  map<string, size_t> word_cound;
  set<string> exclude = {"The", "But", "And", "Or", "An", "A",
		       "the", "but", "and", "or", "an", "a"};
  string word;
  while(cin >> word)
    if(exclude.find(word) == exclude.end())
      {
      auto first = word.begin();
      auto last = word.end();
      while(first != last)
	{
	  if(isupper(*first))
	    *first = tolower(*first);
	  ++first;
	}
      if(ispunct(*(--last))) word.pop_back();
      auto p = word_cound.insert({word, 1});
      if(!p.second)
	++p.first->second;
      // the original one is better
      // this version more operators and expressions
      // original is simpler and easier.
      }
  for(const auto &w : word_cound)
    cout << w.first << " occurs " << w.second
       << ((w.second > 1) ? " times" : " time") << endl;
}

Exercise 11.21

1
2
3
4
5
6
// map<string, size_t> word_count
// string word
// while(cin >> word) ++word_count.insert({word, 0}).first->second;
// see the privileges of operators in P147
// while(cin >> word) ++((((word_count.insert)({word, 0})).first)->second)

Exercise 11.22

1
2
// pair<map<string, vector<int>>::iterator, bool> sample = map<string, vector<int>> map_sample.insert(pair<string, vector<int>>)

Exercise 11.23

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
int main()
{
  multimap<string, string> family;
  // family.insert({{"Johnson", "Tom"}, {"Johnson", "Jack"}});
  family.insert({"Johnson", "Tom"});
  family.insert({"Johnson", "Jack"});
  family.insert({"Johnson", "Lily"});
  family.insert({"Johnson", "Joe"});
  for(const auto &p : family)
    {
      cout << "Family " << p.first
	 << " Children's names " << p.second << endl;
    }
}

Exercise 11.24

1
2
3
4
// map<int, int> m;
// m[0] = 1;
// add a new element of pair<int, int>(0, 1) to m of type map<int, int>.

Exercise 11.25

1
2
3
4
5
6
// vector<int> v;
// v[0] = 1;
// illegal, there is no element in v of type vector<int>
// for vector, trying to access a non-exist element is forbidden.
// that is an 'out of range' error.

Exercise 11.26

1
2
3
4
// map<string, int> m
// string index;
// int &i = m[index]

Exercise 11.27

1
2
3
// c.count(k): try to determine the amount of keyword in container c, if c is a multiset or a multimap
// c.find(k): try to determine the existence of keyword in container c, but not intend to modify c.

Exercise 11.28

1
2
3
4
5
6
int main()
{
  map<string, vector<int>> m;
  map<string, vector<int>>::iterator iter = m.find("exist");
}

Exercise 11.29

1
2
3
4
5
// if keywoed not cotained in cotainer c:
// c.upper_bound(k): returns an iterator which points to the first element whose keyword is larger than k; if k is larger than any keyword in c, returns an end off iterator of c.
// c.lower_bound(k): same sa c.upper_bound(k) in that suitation.
// c.equal_range(k): returns a pair whose first is same as c.lower_bound() illustrated above, and the second is same as c.upper_bound() illustrated above.

Exercise 11.30

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// pos.first->second
// equals to:
// (pos.first)->second
// and also:
// (*(pos.first)).second
// pos: pair<map<string, string>::iterator, map<string, string>::iterator>
// pos.first: map<string, string>::iterator
// *(pos.first): map<string, string>::value_type
// (*(pos.first)).second: map<string, string>::mapped_type

Exercise 11.31

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
void safe_erase(multimap<string, string> &authors, string author)
{
  multimap<string, string>::iterator iter;
  while((iter = authors.find(author)) != authors.end())
    authors.erase(iter);
}
int main()
{
  multimap<string, string> authors ={{"tom", "abc"}, {"tom", "ddd"}, {"jack", "cde"}, {"levis", "ddd"}, {"jane", "eee"}};
  safe_erase(authors, "tom");
  for(const auto &p : authors) cout << p.first << " " << p.second << endl;
}

Exercise 11.32

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
int main()
{
  multimap<string, string> authors =
    {{"tom", "abc"},
     {"tom", "bde"},
     {"jack", "cde"},
     {"levis", "ddd"},
     {"jane", "eee"}};
  map<string, multiset<string>> order_authors;
  for(const auto &author : authors)
    order_authors[author.first].insert(author.second);
  for(const auto &author : order_authors)
    {
      cout << author.first << ": ";
      for(const auto &work : author.second)
      cout << work << " ";
      cout << endl;
    }
}

Exercise 11.33

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
map<string, string> buildMap(ifstream &map_file)
{
  map<string, string> trans_map;
  string key, value;
  while(map_file >> key && getline(map_file, value))
    {
      if(value.size() > 1)
      trans_map[key] = value.substr(1);
      else
      throw runtime_error("no rule for " + key);
    }
  return trans_map;
}
const string &transform(const string &s, const map<string, string> &m)
{
  auto map_it = m.find(s);
  if(map_it != m.cend())
    return map_it->second;
  else
    return s;
}
void word_transfrom(ifstream &map_file, ifstream &input)
{
  auto trans_map = buildMap(map_file);
  string text;
  while(getline(input, text))
    {
      istringstream stream(text);
      string word;
      bool firstword = true;
      while(stream >> word)
      {
	if(firstword) firstword = false;
	else cout << " ";
	cout << transform(word, trans_map);
      }
      cout << endl;
    }
}
int main(int argc, char *argv[])
{
  if(argc != 3) return -1;
  auto map_file = ifstream(argv[1]);
  auto input = ifstream(argv[2]);
  word_transfrom(map_file, input);
}

Exercise 11.34

1
2
3
// illegal, won't compile.
// a const map does not support subscript operator.

Exercise 11.35

1
2
3
// if that key already contained in trans_map, this expression does nothing,
// the specified new element is not inserted to trans_map, the most first one with same keyword is not replaced.

Exercise 11.36

1
2
3
4
5
// This would cause runtime_error
// outputs:
// terminate called after throwing an instance of 'std::runtime_error'
// what(): no rule for pic

Exercise 11.37

1
2
3
4
5
6
7
// advantages of unordered associative container:
// useful when the order of elements could not be arranged;
// sometimes the cost of maintaining order of elements in ordered associative container is really high.
// advantages of ordered associative container:
// elements in an order in a straight way, user-friendly;
// convenient to apply self defined type as keyword type in an ordered associative container.

Exercise 11.38a

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int main()
{
  unordered_map<string, size_t> word_cound;
  set<string> exclude = {"The", "But", "And", "Or", "An", "A",
			 "the", "but", "and", "or", "an", "a"};
  string word;
  while(cin >> word)
    if(exclude.find(word) == exclude.end())
      ++word_cound[word];
  for(const auto &w : word_cound)
    cout << w.first << " occurs " << w.second
	 << ((w.second > 1) ? " times" : " time") << endl;
}

Exercise 11.38b

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
unordered_map<string, string> buildMap(ifstream &map_file)
{
  unordered_map<string, string> trans_map;
  string key, value;
  while(map_file >> key && getline(map_file, value))
    {
      if(value.size() > 1)
	trans_map[key] = value.substr(1);
      else
	throw runtime_error("no rule for " + key);
    }
  return trans_map;
}

const string &transform(const string &s, const unordered_map<string, string> &m)
{
  auto map_it = m.find(s);
  if(map_it != m.cend())
    return map_it->second;
  else
    return s;
}

void word_transfrom(ifstream &map_file, ifstream &input)
{
  auto trans_map = buildMap(map_file);
  string text;
  while(getline(input, text))
    {
      istringstream stream(text);
      string word;
      bool firstword = true;
      while(stream >> word)
	{
	  if(firstword) firstword = false;
	  else cout << " ";
	  cout << transform(word, trans_map);
	}
      cout << endl;
    }
}

int main(int argc, char *argv[])
{
  if(argc != 3) return -1;
  auto map_file = ifstream(argv[1]);
  auto input = ifstream(argv[2]);
  word_transfrom(map_file, input);
}