计算字符串中所有字符的函数 - C++

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17628657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:18:37  来源:igfitidea点击:

Function to count all characters in a string - C++

c++

提问by user5944916

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:

我想用 C++ 写一个函数,它计算字符串中的所有字符。# 我有一个名为 input 的字符串,程序的用户可以在其中输入一个句子,重要的字母我存储在这样的字符串字母表中:

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.

以及一个用于存储字母出现频率的向量,例如A位于位置0,B位于位置0,依此类推。

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:

例如,如果输入是“HELLO”,程序会输出:

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.

所以你看,例如字母“L”在字符串中出现了两次,但“L”的结果是 24,因为“L”在字母表中的第 12 位。

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 >> inputbut getline(cin, input);is right.

编辑:之前我有cin >> input但是getline(cin, input);对的。

回答by Tom van der Woerdt

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;
}

回答by KillianDS

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 Nbeing the length of the input string and Mthe 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.

由于访问无序映射应该按照O(1)this的顺序将导致复杂度为O(N+M)N输入字符串M的长度和输出字符串的长度。您也许可以改进 counts 和 counts2 之间的复制,或者完全消除额外的地图,我在写这篇文章时有点着急;)。您也可以重新将输出放入向量中,但我会将其留作练习。

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:

另一种变体是将您的字母表存储在一个集合中并if(alphabetset.count(c))在第一个循环中执行一个而不执行第二个循环。这将具有复杂性O(N*log(M)),这也足够好,并且代码更简单一些:

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

当然,如果您的输入集具有一些数学属性(例如是一个精确范围),您可以使用 Tom van der Woerdt 之类的解决方案,因为这将是O(N)并且您无法比这更快。

回答by Edison Chang

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

回答by user5944916

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;
    }

回答by Akshat Gupta

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;
}

回答by Sam Mokari

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;

回答by Scuodder

#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]!='
 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] );  
}
'){ 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.....*/

回答by Scuodder

you can also do 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;

回答by Branko Dimitrijevic

You could do something like this:

你可以这样做:

'I'     4
'M'     1
'P'     2
'S'     4

This prints...

这印...

// 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]);

...since we count onlythe characters from alphabet.

......因为我们算只有从人物alphabet

Replace std::unordered_mapwith std::mapif you wish to guarantee ordered results (they are ordered in the example above by accident).

更换std::unordered_mapstd::map,如果你想保证有序的结果(它们被意外下令在上面的例子)。

回答by syam

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:

正如@KillianDS 在评论中所提到的,如果您想要一个通用的解决方案(即可以变化的“字母表”),最简单的方法可能是计算每个可能字符的出现次数,然后根据您的实际字母表对其进行过滤:

##代码##

Note: when counting items, better use size_tthan longor int.

注:计数的项目,更好地利用时size_tlongint