Reputation:
I want to write a functioin in C++, which counts all characters in a string.# I have a string called input, in which the user of the program can enter a sentence, the letters that are important I stored in a string alphabet like this:
string alphabet {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
and a vector that is used to store the frequency of occurrence of the letters, e.g. A is located on place 0, B on place 0, and so on.
vector<long> letterCount (26);
I have written the function like I think it should work, and it seems that it is able to figure out the occurences of the characters but after that this figure is multiplied by the place of the letter in the alphabet. Here is the function:
long countLetters(int& p) {
for(int i = 0; i < alphabet.size(); ++i) {
for(long j = 0; j < count(input.begin(), input.end(), alphabet.at(i)) {
countLetters.at(i)++;
}
}
return letterCount.at(p);
}
For example, if the input is "HELLO" the programs puts out:
E : 5
H : 8
L : 24
O : 15
So you see, for example the letter 'L' is contained two times in the string, but the result for 'L' is 24, because 'L' is at place 12 in the alphabet.
Please help, if you realize what my problem is.
EDIT: I've found a way that works, at least partially:
long countLetters(int& p) {
for(size_t i = 0; i < input.length(); ++i) {
for(size_t j = 0; j < alphabet.length(); ++j) {
letterCount.at(j) = count(input.begin(), input.end(), alphabet.at(j));
}
}
return letterCount.at(p);
}
But when entering two or more words the function only figures out the letter-occurences in the first word. How do I analyze more words?
EDIT: before I had cin >> input
but getline(cin, input);
is right.
Upvotes: 4
Views: 35602
Reputation: 13
The string can be taken as an argument from the user.
cin >> inputString;
unordered_map<char, int> characterMap;
for (char c : inputString){
characterMap[c]++;
}
for (std::pair<char, int> characterCount : characterMap) { // Alternatively use 'auto' as type
cout << characterCount.first << " count: " << characterCount.second << endl;
}
Upvotes: 1
Reputation: 1
#include<iostream>
#include <conio.h>
using namespace std;
int main (){
char str[50];
cin.getline(str,50);
int arr[1234]={0};
///extraction of every character
int i=0;
while(str[i]!='\0'){
arr[str[i]-' ']++; /* converting characters into integer type implicitly
and storing freq of the ASCII characters at that
position of the array.' ' space char is just a
reference point... */
i++;
}
///show character freq
for (i=0;i<256;i++) {
if (arr[i]!=0)
cout <<"letter "<<char(i+' ')<<" is present "<<arr[i]<<" times "<<endl;
}
return 0;
}
/* the arr array contains freq of all the characters and symbols occuring in
a string after ' '(space) character ..so beware of entering the characters
that are before ' ' on the standard ASCII table and your program should run
fine..if you want to do so just replace the ' ' everywhere with the first
character of the ASCII table.....*/
Upvotes: 0
Reputation: 471
Test this macro
#define FOR_ALL(cont , block)\
for (const auto &itr : cont)\
block;
And this part of Code
map<char, int> countLetters;
FOR_ALL(str, countLetters[itr]++);
And for printing the result
for (const auto &element : m)
cout << element.first << ' ' << element.second<<endl;
Upvotes: 0
Reputation: 11
char arr[] = {"aaabbaccdaadac"};
map<char,int> mymap;
for(int i= 0 ;i<strlen(arr);i++)
{
mymap.insert(pair<char,int>(arr[i],0));
auto it = mymap.find(arr[i]);
++it->second;
mymap.insert(pair<char,int>(arr[i],it->second));
}
map<char, int> ::iterator mapit;
for(mapit = mymap.begin(); mapit != mymap.end() ; mapit++)
{
cout<<mapit->first<< " occurence == " <<mapit->second<<endl;
}
Upvotes: 1
Reputation: 335
This is my version to solve the problem and print the result in descending order.
void printNumofLetterinString(std::string sentence){
int frequencyArray[26]; //FrequencyArray is used to store the frequency
for(int i=0;i<26;i++){ //of the letters and Initialize
frequencyArray[i] = 0; //frequencyArray to all zero.
}
int ascii;
for(int i=0;i<sentence.length();i++){
if(!isalpha(sentence[i])){
continue;
}
ascii = tolower(sentence[i]) - 'a'; //Convert A-Za-z to number between 0-25.
frequencyArray[ascii]++;
}
for(int i=0;i<26;i++){ //Find the biggest number in frequencyArray
int max = frequencyArray[0]; //print it, then set it to zero
int index = 0; //and find the next biggest number.
for(int j=0;j<26;j++){
if(frequencyArray[j] > max){
max = frequencyArray[j];
index = j;
}
}
if(max == 0){
break;
}
char c = index + 'a';
std::cout<<c<<" "<<max<<std::endl;
frequencyArray[index] = 0;
}
}
The result looks like the following
input caaabb
output a 3
b 2
c 1
Upvotes: 1
Reputation: 52107
You could do something like this:
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string input = "MISSISSIPPI yukon.";
// First insert the characters that we want to count.
std::unordered_map<char, size_t> map;
for (auto ch : alphabet)
map[ch] = 0;
// Then count ONLY the inserted characters.
for (auto ch : input) {
auto it = map.find(ch);
if (it != map.end())
++it->second;
}
for (auto pair : map)
if (pair.second > 0)
std::cout << '\'' << pair.first << "\'\t" << pair.second << std::endl;
This prints...
'I' 4
'M' 1
'P' 2
'S' 4
...since we count only the characters from alphabet
.
Replace std::unordered_map
with std::map
if you wish to guarantee ordered results (they are ordered in the example above by accident).
Upvotes: 0
Reputation:
you can also do this :
char *x = "cmnasdkASFSAFASDisdajkhasdfjqwedz" ; // work UPPER , lower
static int c[26] ;
int main ( void ) {
while ( *x ) {
int ndx= *x - (islower(*x) ? 'a' : 'A') ;
c[ ndx] += isalpha(*x++) ? 1 : 0 ;
}
for ( int i =0;i<26;i++) printf ( "\n%d", c[i] );
}
Upvotes: 0
Reputation: 17176
I would do this in two steps like this:
#include <unordered_map>
#include <algorithm>
#include <string>
#include <iostream>
int main()
{
std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
std::string input = "hello world";
std::unordered_map<char, unsigned int> counts;
std::unordered_map<char, unsigned int> counts2;
std::for_each(std::begin(input), std::end(input), [&counts](char c) {
counts[c]++;
});
std::for_each(std::begin(alphabet), std::end(alphabet), [&counts, &counts2] (char c) {
const auto& it = counts.find(c);
if( it != counts.end()) counts2.insert(*it);
});
for(auto& kv: counts2)
{
std::cout << kv.first << ": " << kv.second << "\n";
}
return 0;
}
As access to an unordered map should be in the order of O(1)
this will result in a complexity of O(N+M)
, with N
being the length of the input string and M
the length of the output string. You might be able to improve the copying between counts and counts2, or eliminating the extra map altogether, I was a bit in a hurry when writing this up ;). You can also get back to putting the output in a vector, but I'll leave that as an excercise.
Another variant would be to store your alphabet in a set and do an if(alphabetset.count(c))
in the first loop and do not do the second loop. This would have complexity O(N*log(M))
which can also be good enough and the code is a bit simpler:
#include <unordered_map>
#include <algorithm>
#include <string>
#include <iostream>
#include <set>
int main()
{
std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
std::set<char> alphabetset{std::begin(alphabet), std::end(alphabet)};
std::string input = "hello world";
std::unordered_map<char, unsigned int> counts;
std::for_each(std::begin(input), std::end(input), [&counts, &alphabetset](char c) {
if(alphabetset.count(c)) counts[c]++;
});
for(auto& kv: counts)
{
std::cout << kv.first << ": " << kv.second << "\n";
}
return 0;
}
Of course if your input set has some mathematical properties (like being an exact range), you can use a solution like Tom van der Woerdt's, because this will be O(N)
and you can't get faster than that.
Upvotes: 2
Reputation: 15069
As mentioned by @KillianDS in a comment, if you want a generic solution (ie. an "alphabet" that can vary) the easiest way is probably to count the occurrences of every possible character, then filter that depending on your actual alphabet:
// count every possible character
std::array<size_t, (1 << (8 * sizeof(char)))> countChars;
countChars.fill(0);
for (auto i = input.begin(); i != input.end(); ++i)
countChars[*i]++;
// extract only the ones you're interested in
std::vector<size_t> countLetters;
for (auto i = alphabet.begin(); i != alphabet.end(); ++i)
countLetters.push_back(countChars[*i]);
Note: when counting items, better use size_t
than long
or int
.
Upvotes: 0
Reputation: 29965
You're doing some kind of weird double loop. Instead, iterate over the string in a single loop and count it in the right group :
for (int i = 0; i < input.length(); i++) {
char c = input[i];
if (c < 'A' || c > 'Z') continue;
countLetters[c-'A'] += 1;
}
Upvotes: 4