0

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;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Luke
  • 25
  • 3
  • 6
    you want a `std::map` or a `std::vector>` – 463035818_is_not_an_ai Jan 09 '23 at 21:10
  • If you are permitted to use the standard library here is a good solution: [https://stackoverflow.com/questions/67730078/c-how-do-i-frequency-count-characters/67730315#67730315](https://stackoverflow.com/questions/67730078/c-how-do-i-frequency-count-characters/67730315#67730315) – drescherjm Jan 09 '23 at 21:13
  • I dont understand your code. What about `B`, `D`, `F` and all the other characters that you skipped? – 463035818_is_not_an_ai Jan 09 '23 at 21:13
  • 2
    you have variables named `A`,`C`, `E` ... in `main`, they are totally unrelated to members of the struct or the array `letters a[n];`. – 463035818_is_not_an_ai Jan 09 '23 at 21:17
  • 2
    approaching C++ by doing exercises without guiding on what exercise is suitable for your level will not learn you much. You need to learn at least about arrays, perhaps custom structs, to tackle this one – 463035818_is_not_an_ai Jan 09 '23 at 21:26

2 Answers2

0

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Igor G
  • 1,838
  • 6
  • 18
0

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.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • I would suggest a lambda for sorting. `std::sort(frequencies.begin(), frequencies.end(), [](auto a, auto b){ return a.frequency > b.frequency; });` – Chris Jan 10 '23 at 00:39
  • Sorry, I'm old fashioned and believe that standalone functions are easier to read, especially for newbies. :-) – Thomas Matthews Jan 10 '23 at 00:51
  • I would use a `std::(unordered_)map` to count the frequencies, and then create a `std::vector` of `iterator`s to the `map` elements, then sort and display the `vector`. – Remy Lebeau Jan 10 '23 at 01:44
  • 1
    @ThomasMatthews the "simpler" code you have provided is displaying the found letters in descending alphabetical order, not in descending frequency order, which is the actual task given to the OP. – Remy Lebeau Jan 10 '23 at 01:51