Count letters in string

I need to count the number of times each letter appears, and ONLY the ones that appear. I'm at a loss how to do that. Any help is appreciated, thanks!

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
#include <iostream>
using std::string;
using std::getline;
using std::cin;
using std::cout;
using std::endl;

int countWords(const string& input)
{
    int wordCount = 0;
    for ( unsigned int index = 0; index < input.size(); index++ )
    {
        if ( !isalpha(input[index]) && isalpha(input[index - 1]) )
        {
            wordCount++;
        }
    }
    return wordCount;
}

int main()
{
    string inputToParse;
    getline(cin, inputToParse);
    cout << "Number of words: " << countWords(inputToParse) << endl;

    return 0;
}
You're almost there OP. First, rename your function and variables to more accurately reflect what they are doing. This won't have any impact on the performance or function of your code, but it's a pet peeve of mine. Second, your newly named 'count...' function should in some way be aware of what letter it is looking for this is usually done by adding another argument. And third, but probably not last, main needs to keep track of the letters that are being counted and which ones they are. I'd normally suggest a simple custom struct for this duty. Something along the lines of:

1
2
3
4
5
6
7
struct LetterCount
{
      LetterCount(): Count(0), Letter(0) {}

      int Count;
      char Letter;
};


If you can't, or worse won't, use custom classes then things get more annoying.
One solution could be use a std::map<char,int> then you can check if the character has been found already and increment the second value as a counter. In the end you will end up with a map populated with only the chars involved in the text and a count of each.
I'm intrigued by using the map, but I can't for the life of me figure out how to test if it already is in the map.
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
#include <iostream>
#include <string>
#include <map>
using namespace std;

int main()
{
	string str("jafarraf");
	map<char, int> hash;

	for (auto x : str)
	{
		int count = 0;
		for (int i = 0; i < str.length(); i++)
		{
			if (str.at(i) == x)
				count++;
		}
		pair<char, int> p(x, count);
		hash.insert(p);
	}

	map<char, int>::iterator it;
	for (it = hash.begin(); it != hash.end(); it++)
		cout << it->first << "--" << it->second << endl;

	system("pause");
	return 0;
}
ShadowCODE - That works perfectly for me ( I will have to spend some time studying every line of it to totally understand it ) but it's only adding 1 to the value of the first letter found, everything else is still 0. Here is what I have...

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
51
52
53
54
55
#include <iostream>
#include <map>
using std::string;
using std::getline;
using std::cin;
using std::cout;
using std::endl;

int countWords(const string& input)
{
    int wordCount = 0;
    for ( unsigned int index = 0; index < input.size(); index++ )
    {
        if ( !isalpha(input[index]) && isalpha(input[index - 1]) )
        {
            wordCount++;
        }
    }
    return wordCount;
}

void letterCounter(const string& input, std::map<char,int>& letterCount)
{
    for ( auto x : input )
    {
        int count = 0;
            for ( int i = 0; i < input.length(); i++ )
            {
                if ( input.at(i) == x)
                {
                    count ++;
                }
                std::pair<char,int> p(x,count);
                letterCount.insert(p);
            }
    }

    std::map<char,int>::iterator it;
    for ( it = letterCount.begin(); it != letterCount.end(); it++ )
    {
        cout << it->first << " -- " << it->second << endl;
    }
}

int main()
{
    string inputToParse;
    getline(cin, inputToParse);
    cout << "Number of words: " << countWords(inputToParse) << endl;

    std::map<char,int> letterCount;
    letterCounter(inputToParse,letterCount);

    return 0;
}
@Mr D. Really i cannot see why yours does not work properly
Here is the output.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
This is a test.
Number of words: 4
  -- 0
. -- 0
T -- 1
a -- 0
e -- 0
h -- 0
i -- 0
s -- 0
t -- 0

Process returned 0 (0x0)   execution time : 4.210 s
Press any key to continue.
Scope. Mr D's lines 33-34 are within the inner loop.

Frankly, there should not be any inner loop, but exploit the map::find instead.

Pseudo:
* We have taken the next character (x)
* There are exactly two possibilities:
1. The map has key x. Increment the value of that element.
OR
2. The map does not have key x yet. Emplace( x, 1 ) to the map.

Well, there is also third, optional possibility:
0. This is not a character that we will count (e.g. a space).


Style issue:
The letterCounter takes the map as reference, but the caller (main) does not care about the map. The "counting" function does some printing too (a "side effect"). One function, one task.


On the words: my test input was "foobar" and the program says: "words 0".
There is a monster too; what is seriously scary in this:
1
2
3
const std::string input = "foobar";
unsigned int index = 0;
std::cout << input[ index - 1 ]; // Which character is this? 

Hint: see "exception safety" in http://www.cplusplus.com/reference/string/string/operator%5B%5D/
oh, how did i not see lines 33 -34?
Topic archived. No new replies allowed.