统计单词

君子不器 ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ -- 论语


伊始

  • 来源:题目来自于陶老师的码农花园课程;

    陶老师经常说同一道题目,我们需要通过尝试不同的方法去解答来达到练习的效果

问题描述

  • 一个文本文件,假定里面都是由空格分隔的英文单词。单词的数量和最长长度不确定,但系统的内存一定够用
  • 输入:文件名
  • 输出:输出出现次数最多的前20个单词
  • 备注
    1. 文件总单词个数小于20,则输出所有单词
    2. 相同次数的单词可随意输出,只要输出单词个数达到20即可
    3. 空格可以是一个或多个

Solutions

话不多说,这里我们直接给出几个解法供大家参考

Before

  • 定义

    using Words = std::vector<std::string>;  // output type
    using WordFreqs = map<string, int>; // for count word freq
    
    constexpr std::size_t OUT_WORD_NUM = 20;
    
  • 接口设计

    Words count_word(const std::string& file);
    
  • 基础功能

    在给出我们几个解法前,我们先实现一些我们认为的基础功能,供各个解法复用

    1. 打开文件
    std::ifstream open_file(const std::string& file) {
      return std::ifstream{file};
    }
    
    1. 统计词频
    WordFreqs count_word_freq(const std::string& file) {
      auto in = open_file(file);
      map<string, int> words;
      string word;
      while (in >> word) {
        ++words[word];
      }
      return words;
    }
    

解法一

  • 使用vector来保存词频键值对,然后按照词频进行排序即可

    Words count_word_1(const WordFreqs& freqs) {
      vector<pair<string, int>> words{begin(freqs), end(freqs)};
      auto out_nums = min(OUT_WORD_NUM, words.size());
    
      std::partial_sort(begin(words), begin(words) + out_nums, end(words),
                        [](auto& x, auto& y) { return x.second > y.second; });
    
      return copy_range<Words>(words | sliced(0, out_nums) | transformed([](const auto& p) { return p.first; }));
    }
    

解法二

  • 使用multimap来保存词频的value和key,利用反向迭代器来获取次数最多的单词

    auto revers_k_v(const WordFreqs& freqs) {
      return copy_range<multimap<int, string>>(freqs | transformed([](const auto& p) {
        return make_pair(p.second, p.first);
      }));
    }
    
    Words count_word_2(const WordFreqs& freqs) {
      return MakeStream::from(freqs.rbegin(), freqs.rend()) // 利用反向迭代器构建stream 流
          | map_([](const auto& p) { return p.second; })
          | limit(min(OUT_WORD_NUM, words.size()))
          | to_vector();
    }
    

解法三

在解法二的基础上,我们可以指定multimap的比较器,就不需要使用反向迭代器了;

// 传入greater比较器
auto revers_k_v(const WordFreqs& freqs) {
  return copy_range<multimap<int, string, greater<>>>(freqs | transformed([](const auto& p) {
    return make_pair(p.second, p.first);
  }));
}

Words count_word_3(const WordFreqs& freqs) {
  return MakeStream::from(freqs)
      | map_([](const auto& p) { return p.second; })
      | limit(min(OUT_WORD_NUM, freqs.size()))
      | to_vector();
}

解法n

其实还有很多种解法,陶老师给出了7个版本,有兴趣的读者可以多多尝试不同的解法

After

最后,写个测试函数将我们的结果打印出来就可以了

string file = "input.txt";
auto words = count_word(file);
copy(begin(words), end(words), ostream_iterator<string>(cout, " "));

延申讨论

需求变更

  • 变更1

    如果不是输出的个数不是20,而是由用户指定个数呢?

  • 变更2

    次数相同,按照字典序(升序或者降序)输出

  • 变更3

    次数相同,按照字符串在文件里第一次出现的顺序输出

  • 变更4

    加入单词间的分隔符除了空格还有','和’.'等其它指定的字符集

  • ……

应对变化

  • 问:对于复杂的需求变化,我们需要做一个大而全的设计吗?充分考虑未来的变化吗?甚至提前实现一些未来可能出现变化点?

    我们的认为是,不需要;我们提倡用简单来应对变化(抗变化),而不去用大设计去预测或者实现变化;

    对于未来,我们的态度是:“预测未来,绝不是实现未来”

End

独乐乐不如众乐乐,持续学习,共同进步

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352