Reputation: 39
I was wondering if anyone can help me out. I am trying to either use a list or a struct as a container to count the frequency of letters in a text file and am having some trouble figuring out the solution.
I have some code below and was first trying to use a struct
but can't figure out how to easily navigate this object with a pointer. Does anyone have examples of how to add to and walk through entries in a struct
? Isn't a struct
like an expandable container?
If I can use the std::list
I would rather do that but couldn't really find any examples on this site or on the web that were useful enough after reading the std::list
documentation. I need a char
variable and an integer the char
contains the letter found and the integer is the counter of how many times I found each letter.
Can anyone here help?
Thanks.
Code so far:
#include <iostream>
#include <fstream>
#include <list>
using namespace std;
struct LetterBox {
char letter;
size_t frequency;
LetterBox* Next;
LetterBox(char ch, size_t count, LetterBox* ptr)
{
letter = ch;
frequency = count;
Next = ptr;
}
};
int main() {
new LetterBox(' ',0,nullptr);
// new LetterBox(' ',0,nullptr);
int count = 0;
char ch;
string line;
string FileName;
cout << "Enter the name of the textfile: ";
cin >> FileName;
ifstream file (FileName);
if (file.is_open())
while (file.good())
{
while(getline(file, line)) {
for (int i = 0; i < sizeof(line); i++) {
ch = toupper(line[i]);
count++;
cout << ch;
}
}
file.close();
}
else
{
cout << "Unable to open file:" << FileName << endl;
return 1;
}
return 0;
}
Upvotes: 3
Views: 166
Reputation: 3632
Here is an example for which I have used map
and structured binding
for counting the frequency of the letter
New Feature of c++17 used
1.If statement with initializer
- Structure Binding
#include<iostream>
#include<string>
#include<map>
#include<algorithm>
int main()
{
std::map<char,int> counterOfChar;
std::string My("Once upon a time there was a lion who was very funny in reading text and counting them");
std::for_each(My.begin(), My.end(), [&counterOfChar](const char& n)
{ //'if' initialization statements are a C++1z extension
if (auto [iter,success] = counterOfChar.insert(std::make_pair(toupper(n),1) ) ;success == false)
{
counterOfChar[iter->first] = ++iter->second;
}
});
for (const auto &[character,count]:counterOfChar)
{
std::cout<<character<<" "<<count<<std::endl;
}
return 0;
}
Output
17
A 6
C 2
D 2
E 8
F 1
G 2
H 3
I 5
L 1
M 2
N 10
O 5
P 1
R 3
S 2
T 6
U 3
V 1
W 3
X 1
Y 2
Program ended with exit code: 0
Upvotes: 0
Reputation: 16099
You can experiment a bit, using std::map like you use dict in some other languages, it is Quicker, easier, more seductive and already solve problems if you want to support UTF encoding later.
But if you already know it will only be used for ASCII text there is another way.
Your universe for ASCII is 0-255 (actual 0-128 but lets ignore that in case someone use the extended ASCII). This mean that we can actually in reasonable space cover all outcomes with a
std::array<std::size_t, 256> letters= {0};
You can then replace your inner loop with
for (int i = 0; i < sizeof(line); i++) {
ch = toupper(line[i]);
letter[ch]++;
}
And later write out the result
for (char ch = 'A'; ch <= 'Z'; ch++) {
std::cout << "Letter: '" << ch << "' occured " << letter[ch] << " times\n";
}
This should be roughly the same space usage as a std::map
but better locality and far better lookup time. You could get by with using only 27 letters but that adds more conditions.
Upvotes: 1
Reputation: 4473
As others suggested in comments under your question, the std::map
is what do you need. With std::map
you can map the number of occurrences to the corresponding characters.
Here is a simple example:
#include <iostream>
#include <string>
#include <map>
int main() {
std::string hello { "Hello, World!" };
std::map<char, std::size_t> letterCounts;
for(char ch : hello)
letterCounts[ch]++;
for(auto& elem : letterCounts)
std::cout << elem.first << ": " << elem.second << std::endl;
}
The std::list
is good when you intend to use a container with fast insertion and removal abilities. Accessing elements inside an std::list
is slow.
Upvotes: 0