Cory Hall
Cory Hall

Reputation: 39

C++ - No matching constructor

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

Answers (3)

Hariom Singh
Hariom Singh

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

  1. 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

Surt
Surt

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

Akira
Akira

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

Related Questions