In input.txt
, I have a sentence, for example:
HELLO COUNT HOW MANY CHARACTERS ARE HERE AND WHICH CHARACTERS
I have to read input.txt
and count how many characters of each letter are in that sentence. And then, I have to sort those characters in a descending order.
I'll give you an example, there are:
H:7, E:6, L:2, O:3, C:5, W:2, A:7, Y:1, R:6, S:2, I:1, M:1, N:1
A letter indicates which letter it is, and a number indicates how many times that letter appears in the sentence. And when I sort them, it should like this:
H:7, A:7, E:6, R:6, C:5, O:3, L:2, W:2, S:2, Y:1, I:1, M:1, N:1
It doesn't matter which letter is first if they appear the same amount of times.
The problem is that I don't know how to sort them, and how to make that each letter gets printed in a sorted order. I'm new to C so I don't know much.
The only idea I came up with is to put all of those letters into a struct
and then sort it. I've thought about putting them into an array, but I'm not sure how to do that, or if it's possible. So I decided to try it with a struct
, but didn't make it far.
Here's my code:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
struct letters{
int A=0, C=0, E=0, H=0, I=0, L=0, M=0, N=0, O=0, R=0, S=0, W=0, Y=0;
int n=13;
};
int main() {
string str;
int A=0, C=0, E=0, H=0, I=0, L=0, M=0, N=0, O=0, R=0, S=0, W=0, Y=0;
int n=13; // How many letters there are in total
ifstream read("input.txt");
while (getline(read,str)) {
for(char &ch : str) {
// Here I read a letter and if it matches one of those "if statements" it counts it
if(ch == 'A'){
A ;
}
if(ch == 'C'){
C ;
}
if(ch == 'E'){
E ;
}
if(ch == 'H'){
H ;
}
if(ch == 'I'){
I ;
}
if(ch == 'L'){
L ;
}
if(ch == 'M'){
M ;
}
if(ch == 'N'){
N ;
}
if(ch == 'O'){
O ;
}
if(ch == 'R'){
R ;
}
if(ch == 'S'){
S ;
}
if(ch == 'W'){
W ;
}
if(ch == 'Y'){
Y ;
}
}
}
letters a[n];
sort(a, a n); // Trying to sort it and then print everything out like I did below. But I don't know how
// Here I just check if every letter is counted correctly
cout << "A: " << A << endl;
cout << "C: " << C << endl;
cout << "E: " << E << endl;
cout << "H: " << H << endl;
cout << "I: " << I << endl;
cout << "L: " << L << endl;
cout << "M: " << M << endl;
cout << "N: " << N << endl;
cout << "O: " << O << endl;
cout << "R: " << R << endl;
cout << "S: " << S << endl;
cout << "W: " << W << endl;
cout << "Y: " << Y << endl;
read.close();
return 0;
}
CodePudding user response:
Since you need to sort by descending frequency, I recommend having a container of struct:
struct Letter_Frequency
{
char letter;
unsigned int frequency;
};
std::vector<Letter_Frequency> frequencies;
Here's a code fragment showing how to build the container:
while (getline(text_file, text_str))
{
const size_t string_length(text_str.length());
for (size_t str_index = 0U; str_index < string_length; str_index)
{
const char c = text_str[str_index];
// Skip characters that are not a letter.
if (!isalpha(c)) continue;
// Search the container for the letter...
const size_t container_size(frequencies.size());
bool letter_exists = false;
for (size_t container_index = 0U;
container_index < container_size;
container_index)
{
if (frequencies[container_index].letter == c)
{
frequencies[container_index].frequency;
letter_exists = true;
break;
}
}
if (!letter_exists)
{
Letter_Frequency new_letter;
new_letter.letter = c;
new_letter.frequency = 1U;
frequencies.push_back(new_letter);
}
}
}
Since the container is created and filled, time to order descending by frequency. This is performed by writing an ordering function:
bool Order_Descending_By_Frequency(const Letter_Frequency& a,
const Letter_Frequency& b)
{
return a.frequency > b.frequency;
}
To do the sorting:
std::sort(frequencies.begin(), frequencies.end(),
Order_Descending_By_Frequency);
There are other methods to calculate the frequencies and sort descending order by frequency. The above code fragments demonstrate one possibility.
Restrictions and other modifications are left as an exercise for the OP or reader.
Edit 1: Simplicity
A simpler approach would be to use an array and print the array "bottom up".
const unsigned int MAX_LETTERS = 26;
unsigned int frequencies[MAX_LETTERS] = {0};
//...
for (size_t str_index = 0U; str_index < string_length; str_index)
{
const char c = text_str[str_index];
if (isalpha(c))
{
const char upper_c(toupper(c));
frequencies[(upper_c - 'A')];
}
}
for (int index = MAX_LETTERS - 1; index >= 0; --index)
{
if (frequencies[index] > 0)
{
const char letter = 'A' index;
std::cout << letter << ": " << frequencies[index] << "\n";
}
}
In the above code fragment, the frequencies are calculated in a usual method, but the printing starts at the end of the array. No sorting required.
CodePudding user response:
I've thought about putting them into an array, but I'm not sure how to do that, or if it's possible.
That was a good idea, since sorting an array would be an easy thing to do. Also, an array would easily scale to accommodate other letters so that you wouldn't have to change your program to accommodate, say, letter Q
in a new version of input.txt
.
Your question looks like a homework assignment, so please forgive me for not doing it for you all the way. Just think what an element of that array might look like, given that it must contain a letter along with its counter.
You might want to allocate enough array elements to accommodate all possible letters. Arrange the elements in that vector so that finding an element for each letter can be done with simple indexing (no search!). Then read the file, incrementing the counters for each letter encountered. Then sort the array, and print all elements with non-zero counter values.