Can someone explain this code to me? (multiset / string)

I was trying to code out a simple problem earlier today (Take a string that is a word, take each letter from the word, and 'count' the character in it). I was speaking to my mentor about it, and he shot me this code and said: play around with this, I'll explain it to you tomorrow:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <string>
#include <set>
#include <cctype>
using namespace std;
int main()
{
cout << "Enter string: ";
string s;
getline(cin, s);

//from here
multiset<char> ms(s.begin(), s.end());

for(multiset<char>::const_iterator i=ms.begin(); i!=ms.end(); i=ms.upper_bound(*i))
//to here really confuse me
if(isalpha(*i))
cout << *i << '=' << ms.count(*i) << ' ';
cout << endl;

}


I've spent the vast majority of my night reading up on multiset...I am so confused about the part in between my comments. I also don't really understand what the *i is doing.

Can someone please help me make sense of this code?
I believe the last part of the for loop is to move on the next element in the multiset. This is a common pattern for traversing iterators.
closed account (y8h7M4Gy)
1
2
for(multiset<char>::const_iterator i=ms.begin(); i!=ms.end(); i=ms.upper_bound(*i))
multiset<char> ms(s.begin(), s.end());
The first line of code is the declaration of as multiset container named ms which holds items of type char. The multiset will be composed of characters beginning with the first character of the string container named s all the way through to the last character.
Note that s.begin() obtains an iterator to the first element of s, s.end() to the spot after the last. The multiset constructor uses those two iterators to add elements.

Re: the second line of code, Spaggy was close. You use iterators to traverse the container. The for loop says, get me an iterator (i) to the first element, stop the loop when my iterator passes the last element and use upper_bound() to move the iterator.
Note that a multiset container's elements don't need to be unique. Upper_bound() will return an iterator to the position directly after an existing matching one.
eg. Your multiset contains: a a a b b c .. upper_bound(a) gets you an iterator to the first b, upper_bound(b) gets you an iterator to the first c. (lower_bound() and equal_range() are the other options. lower_bound(a) gets you an iterator to the first a and equal_range(a) gets you a pair of iterators, the first a and the first b - both lower_bound() & upper_bound()).
In your example, the for loop is skipping over the repeated elements. The output would be,
a=3
b=2
c=1
Note that s.begin() obtains an iterator to the first element of s, s.end() to the spot after the last. The multiset constructor uses those two iterators to add elements.


So s.begin(), s.end() is basically saying that the for loop should continue to iterate until s.end is reached?

The for loop says, get me an iterator (i) to the first element, stop the loop when my iterator passes the last element and use upper_bound() to move the iterator.


I'm still a bit confused on why ::const_iterator is there. I'm guessing that the ms.begin() and the ms.end() are just stating the start and end of the multiset? The upper bound is being used to iterate to the next letter (or set of letters)?

Thanks for all the help so far.
1) Yes.

2) ::const_iterator is just there because you aren't modifying the data so you don't need a modifiable iterator.

3) Yes, it basically just moves you to the next "set" of letters in the multiset.
Topic archived. No new replies allowed.