C++ 计算每个单词在文件中出现的次数

C++ 计算每个单词在文件中出现的次数,c++,C++,嗨,我正在写一个程序,计算每个字在文件中出现的次数。然后它打印计数在800到1000之间的单词列表,并按计数顺序排序。我一直在记着一个计数器,看第一个单词是否与下一个单词匹配,直到出现一个新单词。大体上,我试图打开文件,逐字读取每个单词,并在while循环中调用sort对向量进行排序。然后,在for循环中遍历所有单词,如果第一个单词等于第二个count++。我不认为这是你保持柜台的方式 代码如下: #include <string> #include <iostream>

嗨,我正在写一个程序,计算每个字在文件中出现的次数。然后它打印计数在800到1000之间的单词列表,并按计数顺序排序。我一直在记着一个计数器,看第一个单词是否与下一个单词匹配,直到出现一个新单词。大体上,我试图打开文件,逐字读取每个单词,并在while循环中调用sort对向量进行排序。然后,在for循环中遍历所有单词,如果第一个单词等于第二个count++。我不认为这是你保持柜台的方式

代码如下:

#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

vector<string> lines;
vector<int> second;
set<string> words;
multiset<string> multiwords;

void readLines(const char *filename)
{
    string line;
    ifstream infile;
    infile.open(filename);
    if (!infile)
    {       
        cerr << filename << " cannot open" << endl; 
          return; 
    }       
    getline(infile, line);
    while (!infile.eof())
    {
        lines.push_back(line);
        getline(infile, line);
    }  
    infile.close();
}

int binary_search(vector<string> &v, int size, int value)
{
    int from = 0;
    int to = size - 1;
    while (from <= to)
    {  
        int mid = (from + to) / 2;
        int mid_count = multiwords.count(v[mid]);
        if (value == mid_count) 
            return mid;
        if (value < mid_count) to = mid - 1;
        else from = mid + 1;
    }
   return from;
}

int main() 
{
    vector<string> words;
    string x;
    ifstream inFile;
    int count = 0;

    inFile.open("bible.txt");
    if (!inFile) 
    {
        cout << "Unable to open file";
        exit(1);
    }
    while (inFile >> x){
        sort(words.begin(), words.end());
    }

    for(int i = 0;i < second.size();i++)
    {
        if(x == x+1)
        {
            count++;
        }
        else
            return;
    }
    inFile.close();
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
矢量线;
向量秒;
设定词语;
多集多字;
无效读线(常量字符*文件名)
{
弦线;
河流充填;
infile.open(文件名);
如果(!infle)
{       

cerr一种更有效的方法是使用出现的单个
映射
,逐个读取单词,并在
m[word]中递增计数器
。计算完所有单词后,在地图上迭代给定范围内的单词,将它们添加到
多重地图中。
。最后转储多重地图的内容,该内容将按出现次数和字母顺序排序…

一种解决方案可能是:仅定义
字母\u
区域设置,以便忽略点刺来自流的uations,并且只从输入流中读取有效的“英语”字母。这样,流将把单词“ways”、“ways.”和“ways!”视为同一个单词“ways”,因为流将忽略“.”和“!”等标点符号

仅结构字母:std::ctype { 字母_only():std::ctype(get_table()){} 静态std::ctype_base::mask const*get_table() { 静态std::vector rc(std::ctype::table_size,std::ctype_base::space); std::fill(&rc['A'],&rc['z'+1],std::ctype_base::alpha); 返回&rc[0]; } };
然后将其用作:

int main()
{
     std::map<std::string, int> wordCount;
     ifstream input;

     //enable reading only english letters only!
     input.imbue(std::locale(std::locale(), new letter_only())); 

     input.open("filename.txt");
     std::string word;
     std::string uppercase_word;
     while(input >> word)
     {
         std::transform(word.begin(), 
                        word.end(), 
                        std::back_inserter(uppercase_word),
                        (int(&)(int))std::toupper); //the cast is needed!
         ++wordCount[uppercase_word];
     }
     for (std::map<std::string, int>::iterator it = wordCount.begin(); 
                                               it != wordCount.end(); 
                                               ++it)
     {
           std::cout << "word = "<< it->first 
                     <<" : count = "<< it->second << std::endl;
     }
}
intmain()
{
映射字数;
ifstream输入;
//启用仅阅读英文字母!
imbue(std::locale(std::locale(),仅新字母_());
打开(“filename.txt”);
字符串字;
std::字符串大写字母;
while(输入>>单词)
{
std::transform(word.begin(),
word.end(),
std::back_inserter(大写单词),
(int(&)(int))std::toupper);//需要演员阵容!
++字数[大写字母];
}
for(std::map::iterator it=wordCount.begin();
it!=wordCount.end();
++(it)
{

我知道直截了当地展示解决方案并不能真正帮助你。然而

我浏览了一下您的代码,看到了许多未使用和混乱的部分。下面是我要做的:

#include <algorithm>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include <vector>

using namespace std;

// types
typedef std::pair<string, size_t> frequency_t;
typedef std::vector<frequency_t> words_t;

// predicates
static bool byDescendingFrequency(const frequency_t& a, const frequency_t& b)
{ return a.second > b.second; }

const struct isGTE // greater than or equal
{ 
    size_t inclusive_threshold;
    bool operator()(const frequency_t& record) const 
        { return record.second >= inclusive_threshold; }
} over1000 = { 1001 }, over800  = { 800 };

int main() 
{
    words_t words;
    {
        map<string, size_t> tally;

        ifstream inFile("bible.txt");
        string s;
        while (inFile >> s)
            tally[s]++;

        remove_copy_if(tally.begin(), tally.end(), 
                       back_inserter(words), over1000);
    }

    words_t::iterator begin = words.begin(),
                      end = partition(begin, words.end(), over800);
    std::sort(begin, end, &byDescendingFrequency);

    for (words_t::const_iterator it=begin; it!=end; it++)
        cout << it->second << "\t" << it->first << endl;
}
:


这两个文件的性能都大约为1.12s,但在将
map
替换为后仅为0.355s。为了好玩,我用c++0x风格编写了一个解决方案,使用

如果没有(类型推断),这种样式将非常笨拙

通过始终按单词和频率维护索引,无需删除、分区或排序单词列表:它们都会在那里

要编译并运行:

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
结构条目
{
字符串字;
大小和频率;
void increment(){freq++;}
};
结构字节{};//标记
struct byfreq{};//标记
int main()
{
使用::boost::lambda::_1;
使用namespace::boost::multi_索引;
多指标集装箱>理货;
ifstream infle(“bible.txt”);
字符串s;
而(填充>>s)
{
auto&lookup=tally.get();
自动it=查找。查找;
if(lookup.end()!=it)
modify(it,boost::bind(&entry::increment,_1));
其他的
插入({s,1});
}

BOOST_FOREACH(auto e,tally.get().range)(800很抱歉,我不知道它为什么在我的代码开始时这样做。@Chris别担心,为您修复了这个问题,您真的问了问题吗?保留了一个计数器吗?另外,我很想使用sort | uniq-c(可能带有sed来分割多字行)如果这不是为了家庭作业。在编写解决方案时,我可能会使用这种设计模式,但哈希表如果更复杂,效率会更高。您应该考虑一下为什么要在
main()中的
for
循环中返回
ing
。我不熟悉map,怎么做呢?它很简单:
#include;map m;while(/*get word as string*/){m[word]++;}
在网上很容易找到
地图的例子,我建议你查一下。@Nawaz,这是什么打印出来的?@Chris:这会打印单词及其计数。
'It'
是一个迭代器,用于迭代地图的元素,该元素由两个项目组成:
string
int
(即word,count)。
it->first
是单词,而
it->second
是计数。为什么不运行此代码并查看输出?@Nawaz,我得到一个返回行插入器(大写字母)的错误…我取出了所有的std::并使用名称空间std;在顶部,我如何使它只打印出800到1000之间的计数?@Nawaz:你完全值得我投票,因为你实际上在野外植入了ctype。这是我第一次在约瑟蒂斯书之外看到它!@Chris:随时。顺便说一句,习惯上使用投票按钮,而不是在评论中说谢谢:)(例如)
#include <algorithm>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include <vector>

using namespace std;

// types
typedef std::pair<string, size_t> frequency_t;
typedef std::vector<frequency_t> words_t;

// predicates
static bool byDescendingFrequency(const frequency_t& a, const frequency_t& b)
{ return a.second > b.second; }

const struct isGTE // greater than or equal
{ 
    size_t inclusive_threshold;
    bool operator()(const frequency_t& record) const 
        { return record.second >= inclusive_threshold; }
} over1000 = { 1001 }, over800  = { 800 };

int main() 
{
    words_t words;
    {
        map<string, size_t> tally;

        ifstream inFile("bible.txt");
        string s;
        while (inFile >> s)
            tally[s]++;

        remove_copy_if(tally.begin(), tally.end(), 
                       back_inserter(words), over1000);
    }

    words_t::iterator begin = words.begin(),
                      end = partition(begin, words.end(), over800);
    std::sort(begin, end, &byDescendingFrequency);

    for (words_t::const_iterator it=begin; it!=end; it++)
        cout << it->second << "\t" << it->first << endl;
}
993 because
981 men
967 day
954 over
953 God,
910 she
895 among
894 these
886 did
873 put
868 thine
864 hand
853 great
847 sons
846 brought
845 down
819 you,
811 so
995 tuum
993 filius
993 nec
966 suum
949 meum
930 sum
919 suis
907 contra
902 dicens
879 tui
872 quid
865 Domine
863 Hierusalem
859 suam
839 suo
835 ipse
825 omnis
811 erant
802 se
g++ --std=c++0x -O3 test.cpp -o test
curl ftp://ftp.funet.fi/pub/doc/bible/texts/english/av.tar.gz |
    tar xzO | sed 's/^[ 0-9:]\+//' > bible.txt
time ./test
#include <boost/foreach.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <fstream>
#include <iostream>
#include <string>

using namespace std;

struct entry 
{
    string word;
    size_t freq;
    void increment() { freq++; }
};

struct byword {}; // TAG
struct byfreq {}; // TAG

int main() 
{
    using ::boost::lambda::_1;
    using namespace ::boost::multi_index;
    multi_index_container<entry, indexed_by< // sequenced<>,
            ordered_unique    <tag<byword>, member<entry,string,&entry::word> >, // alphabetically
            ordered_non_unique<tag<byfreq>, member<entry,size_t,&entry::freq> > // by frequency
                > > tally;

    ifstream inFile("bible.txt");
    string s;
    while (inFile>>s)
    {
        auto& lookup = tally.get<byword>();
        auto it = lookup.find(s);

        if (lookup.end() != it)
            lookup.modify(it, boost::bind(&entry::increment, _1));
        else
            lookup.insert({s, 1});
    }

    BOOST_FOREACH(auto e, tally.get<byfreq>().range(800 <= _1, _1 <= 1000))
        cout << e.freq << "\t" << e.word << endl;

}