統(tǒng)計(jì)單詞

君子不器 ?????????????????????????? -- 論語(yǔ)


伊始

  • 來(lái)源:題目來(lái)自于陶老師的碼農(nóng)花園課程丹拯;

    陶老師經(jīng)常說(shuō)同一道題目站超,我們需要通過(guò)嘗試不同的方法去解答來(lái)達(dá)到練習(xí)的效果

問題描述

  • 一個(gè)文本文件,假定里面都是由空格分隔的英文單詞乖酬。單詞的數(shù)量和最長(zhǎng)長(zhǎng)度不確定死相,但系統(tǒng)的內(nèi)存一定夠用
  • 輸入:文件名
  • 輸出:輸出出現(xiàn)次數(shù)最多的前20個(gè)單詞
  • 備注
    1. 文件總單詞個(gè)數(shù)小于20,則輸出所有單詞
    2. 相同次數(shù)的單詞可隨意輸出剑刑,只要輸出單詞個(gè)數(shù)達(dá)到20即可
    3. 空格可以是一個(gè)或多個(gè)

Solutions

話不多說(shuō)媳纬,這里我們直接給出幾個(gè)解法供大家參考

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;
    
  • 接口設(shè)計(jì)

    Words count_word(const std::string& file);
    
  • 基礎(chǔ)功能

    在給出我們幾個(gè)解法前嗅战,我們先實(shí)現(xiàn)一些我們認(rèn)為的基礎(chǔ)功能飘言,供各個(gè)解法復(fù)用

    1. 打開文件
    std::ifstream open_file(const std::string& file) {
      return std::ifstream{file};
    }
    
    1. 統(tǒng)計(jì)詞頻
    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來(lái)保存詞頻鍵值對(duì)邮府,然后按照詞頻進(jìn)行排序即可

    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來(lái)保存詞頻的value和key骨杂,利用反向迭代器來(lái)獲取次數(shù)最多的單詞

    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()) // 利用反向迭代器構(gòu)建stream 流
          | map_([](const auto& p) { return p.second; })
          | limit(min(OUT_WORD_NUM, words.size()))
          | to_vector();
    }
    

解法三

在解法二的基礎(chǔ)上环揽,我們可以指定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

其實(shí)還有很多種解法式矫,陶老師給出了7個(gè)版本狸驳,有興趣的讀者可以多多嘗試不同的解法

After

最后预明,寫個(gè)測(cè)試函數(shù)將我們的結(jié)果打印出來(lái)就可以了

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

延申討論

需求變更

  • 變更1

    如果不是輸出的個(gè)數(shù)不是20,而是由用戶指定個(gè)數(shù)呢耙箍?

  • 變更2

    次數(shù)相同撰糠,按照字典序(升序或者降序)輸出

  • 變更3

    次數(shù)相同,按照字符串在文件里第一次出現(xiàn)的順序輸出

  • 變更4

    加入單詞間的分隔符除了空格還有','和’.'等其它指定的字符集

  • ……

應(yīng)對(duì)變化

  • 問:對(duì)于復(fù)雜的需求變化辩昆,我們需要做一個(gè)大而全的設(shè)計(jì)嗎阅酪?充分考慮未來(lái)的變化嗎?甚至提前實(shí)現(xiàn)一些未來(lái)可能出現(xiàn)變化點(diǎn)?

    我們的認(rèn)為是术辐,不需要砚尽;我們提倡用簡(jiǎn)單來(lái)應(yīng)對(duì)變化(抗變化),而不去用大設(shè)計(jì)去預(yù)測(cè)或者實(shí)現(xiàn)變化辉词;

    對(duì)于未來(lái)必孤,我們的態(tài)度是:“預(yù)測(cè)未來(lái),絕不是實(shí)現(xiàn)未來(lái)”

End

獨(dú)樂樂不如眾樂樂瑞躺,持續(xù)學(xué)習(xí)敷搪,共同進(jìn)步

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市隘蝎,隨后出現(xiàn)的幾起案子购啄,更是在濱河造成了極大的恐慌,老刑警劉巖嘱么,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狮含,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡曼振,警方通過(guò)查閱死者的電腦和手機(jī)几迄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冰评,“玉大人映胁,你說(shuō)我怎么就攤上這事〖籽牛” “怎么了解孙?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)抛人。 經(jīng)常有香客問我弛姜,道長(zhǎng),這世上最難降的妖魔是什么妖枚? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任廷臼,我火速辦了婚禮,結(jié)果婚禮上绝页,老公的妹妹穿的比我還像新娘荠商。我一直安慰自己,他們只是感情好续誉,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布莱没。 她就那樣靜靜地躺著,像睡著了一般酷鸦。 火紅的嫁衣襯著肌膚如雪饰躲。 梳的紋絲不亂的頭發(fā)上朴译,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音属铁,去河邊找鬼。 笑死躬翁,一個(gè)胖子當(dāng)著我的面吹牛焦蘑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盒发,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼例嘱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了宁舰?” 一聲冷哼從身側(cè)響起拼卵,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛮艰,沒想到半個(gè)月后腋腮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡壤蚜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年即寡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袜刷。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡聪富,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出著蟹,到底是詐尸還是另有隱情墩蔓,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布萧豆,位于F島的核電站奸披,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏炕横。R本人自食惡果不足惜源内,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望份殿。 院中可真熱鬧膜钓,春花似錦、人聲如沸卿嘲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拾枣。三九已至沃疮,卻和暖如春盒让,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背司蔬。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工邑茄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人俊啼。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓肺缕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親授帕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子同木,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359