Frequency Number

TW_黑珍珠號(hào)_陳祥梅

Frequency Number 需求

一個(gè) Node.js 小程序,它可以處理一段字符串信息穴张,這段字符串信息是由英文單詞組成,每?jī)蓚€(gè)單詞之間有空格找颓,處理結(jié)果也為一段字符串叮贩,這個(gè)字符串應(yīng)該每行只顯示一個(gè)單詞和它的數(shù)量佛析,并且按出現(xiàn)頻率倒序排列寸莫。

使用TDD編程流程如下:

  1. Taking 分解
  2. Jasmine 測(cè)試代碼
  3. JavaScript 實(shí)現(xiàn)代碼
  4. Nodejs 單元測(cè)試
  5. git 提交管理代碼

重復(fù) 2 档冬、3、4披坏、 5直至符合題目要求盐数,然后將項(xiàng)目保存到 git 遠(yuǎn)程倉(cāng)庫(kù)。


Tasking 分解圖

FrequencyNumber Tasking 分解

代碼模塊及測(cè)試用例

測(cè)試用例
輸入 輸出
it it 1
it will it 1 will 1
it will be it will 1 be 1 it 2
it [多個(gè)空格] will it will 1 it 2
主函數(shù)

實(shí)現(xiàn)代碼如下

function main(String){
    if(String === '')
        return String;
    let wordsString = splitString(String);
    let wordsFrequency = countFreqy(wordsString);
    let result = sortFrequency(wordsFrequency);
    return format(result);
}

測(cè)試代碼如下

describe('test for main',function(){
    it('return the result given the string ',function(){
        expect(frequencyNumber.main('it')).toEqual('it 1');
    });

    it('return the result given the string ',function(){
        expect(frequencyNumber.main('it will')).toEqual('it 1\r\nwill 1');
    });

    it('return the result given the string ',function(){
        expect(frequencyNumber.main('it will be it ')).toEqual('will 1\r\nbe 1\r\nit 2');
    });

    it('return the result given the string ',function(){
        expect(frequencyNumber.main('   it will it     ')).toEqual('will 1\r\nit 2');
    });
});

包含代碼模塊如下:

1. split String :將一個(gè)含有空格的英文單詞字符串分解為一個(gè)個(gè)單詞

將傳入的字符串 String 用 split() 方法進(jìn)行分割。
考慮到兩種特殊情況:

  1. String 開始及結(jié)束有空格
    利用正則先去除前后空格攻旦,即 String.replace(/(^\s*)|(\s*$)/g,'');
  2. String 單詞中間有空格
    按照多個(gè)空格分割單詞牢屋,即 String.split(/\s+/)

實(shí)現(xiàn)代碼如下

function splitString(String) {
    String = String.replace(/(^\s*)|(\s*$)/g,'');
    let wordsString = String.split(/\s+/);
    return wordsString;
}

測(cè)試代碼如下

describe('split String to words', function(){

        it('return null given null', function(){
            expect(frequencyNumber.splitString('')).toEqual('');
        });

        it('return one word given one word ', function(){
            expect(frequencyNumber.splitString('it')).toEqual(['it']);
        });

        it('return two word given two word', function(){
            expect(frequencyNumber.splitString('it will')).toEqual(['it','will']);
        });

        it('return three word given three word ', function(){
            expect(frequencyNumber.splitString('it will get')).toEqual(['it', 'will', 'get']);
        });

        it('return two word given two word with some blanks', function(){
            expect(frequencyNumber.splitString('   it  will  ')).toEqual(['it','will']);
        });
    }
);

2. count frequency :計(jì)算每個(gè)單詞出現(xiàn)頻率

JS 中有類似于 Java 中 Map 鍵值對(duì)(key-value) 的數(shù)據(jù)結(jié)構(gòu) Map類,并且同Java一樣key值唯一,在此定義了 Map 數(shù)組 wordsFrequency[] 用于存放不同單詞 word 及它們分別對(duì)應(yīng)的頻率 count 怀估。
統(tǒng)計(jì)頻率有兩種方法:

  1. 定義數(shù)組 words[] ,利用 indexOf()存在返回其在數(shù)組中位置 index,不存在則返回 -1)方法查找 word[] 數(shù)組是否存在此單詞:
    不存在:則將其單詞及頻率(初始為1)作為一個(gè) Map 存放到 wordsFrequency[] 數(shù)組康铭,單詞 words[] 數(shù)組中从藤;
    在其整個(gè)過程每個(gè)單詞在 word[] 數(shù)組中的位置與 wordsFrequency[] 位置相同(即數(shù)組下標(biāo)相同)
    存在:將 wordsFrequency[] 此位置 (即利用indexof() 求出的index) 的元素中的 count 自加一即可锁蠕。
  2. 定義 Map wor荣倾,利用 Map 中鍵值唯一骑丸,例如
    wor = { key1: 1, key2: 2}
    wor[key1] 值 為 1(因 wor 中 已存在 key 值 key1),
    wor[key3] 值 為 undefined(wor 中不存在 key3)
    以此為單詞是否存在于 wordsFrequency[] 的判定條件:
    不存在:將 word 及 count 存入 wordsFrequency[] 數(shù)組中通危,將word作為key存入 wor 中推姻,其值等于此單詞在 wordsFrequency[] 數(shù)組中位置;
    存在:將 wordFrequency[] 對(duì)應(yīng)單詞頻率自加一忍燥。

兩種方法均可實(shí)現(xiàn)厂捞,按實(shí)際情況自行選擇即可靡馁。

實(shí)現(xiàn)代碼如下

function countFreqy(wordsString){
    var count = new Array;
    var words = new Array;
    var wordsFrequency = new Array;
    var cou;
    var wor = {};
    var index;
    for(var i = 0, len = wordsString.length; i < len; i ++ ){
       /* 利用數(shù)組作媒介
       if( (index = words.indexOf(wordsString[i])) === -1){
            words.push(wordsString[i]);
            wordsFrequency.push({word: wordsString[i], count: 1});
        }else{
            wordsFrequency[index].count ++;
        }*/

       //利用Map類key值唯一
        if(wor[wordsString[i]] === undefined ){
            wordsFrequency.push({word: wordsString[i], count:1});
            wor[wordsString[i]] = wordsFrequency.length - 1;
        }else {
            wordsFrequency[wor[wordsString[i]]].count ++;
        }
    }
    return wordsFrequency;

測(cè)試代碼如下

describe('count the Frequency of words',function () {

    it ('return one word and its frequency given one word', function () {
        expect(frequencyNumber.countFreqy(['it'])).toEqual("it 1");
    });

   it ('return two word and their own frequency given two different word', function () {
        expect(frequencyNumber.countFreqy(['it','is'])).toEqual("it 1\r\nis 1");
    });

    it ('return one word and their own frequency given two same word', function () {
        expect(frequencyNumber.countFreqy(['it','it'])).toEqual("it 2");
    });

});
3. sortFrequency: 按照單詞出現(xiàn)的頻率升序排序

此方法利用 JS 中已有的 sort() 方法,自定義按照value值排序的 compare() 函數(shù)實(shí)現(xiàn)。關(guān)于sort()方法語法規(guī)則可參考 W3School對(duì)sort()的介紹 侠畔。

實(shí)現(xiàn)代碼如下

function compare(property){
    return function(a,b){
        return a[property] - b[property];
    }
}
function sortFrequency(wordsFrequency){
    wordsFrequency.sort(compare('count'));
    return wordsFrequency;
}

測(cè)試代碼如下

describe ('sort the Frequency of the words',function(){
    it('return the result in sequence given the random result',function(){
        expect(frequencyNumber.sortFrequency([{word: 'it',count : 2},{word:'will',count:1}])).toEqual("will 1\r\nit 2");
    });
    it('return the result in sequence given the random result',function(){
        expect(frequencyNumber.sortFrequency([{word: 'it',count : 1},{word:'will',count:2},{}])).toEqual("it 1\r\nwill 2");
    });
});
4. format: 格式化結(jié)果,使其符合題目要求

實(shí)現(xiàn)代碼如下

function  format( wordsFrequency) {
    var result = ''
    for(var i = 0,len =  wordsFrequency.length; i < len; i ++){
        if(i > 0){
            result += '\r\n';
        }
        result = result +  wordsFrequency[i].word + ' ' +  wordsFrequency[i].count;
    }
    return result;
}

完整代碼

完整實(shí)現(xiàn)代碼如下

function main(String){
    if(String === '')
        return String;
    let wordsString = splitString(String);
    let wordsFrequency = countFreqy(wordsString);
    let result = sortFrequency(wordsFrequency);
    return format(result);

}

function splitString(String) {
    String = String.replace(/(^\s*)|(\s*$)/g,'');
    let wordsString = String.split(/\s+/);
    return wordsString;
}

function countFreqy(wordsString){
    let count = new Array;
    let words = new Array;
    let wordsFrequency = new Array;
    let cou;
    let wor = {};
    let index;
    for(var i = 0, len = wordsString.length; i < len; i ++ ){
       /* 利用數(shù)組作媒介排序
       if( (index = words.indexOf(wordsString[i])) === -1){
            words.push(wordsString[i]);
            wordsFrequency.push({word: wordsString[i], count: 1});
        }else{
            wordsFrequency[index].count ++;
        }*/

       //利用Json對(duì)象key值唯一排序
        if(wor[wordsString[i]] === undefined ){
            wordsFrequency.push({word: wordsString[i], count:1});
            wor[wordsString[i]] = wordsFrequency.length - 1;
        }else {
            wordsFrequency[wor[wordsString[i]]].count ++;
        }
    }
    return wordsFrequency;
}

function compare(property){
    return function(a,b){
        return a[property] - b[property];
    }
}
function sortFrequency(wordsFrequency){
    wordsFrequency.sort(compare('count'));
    return wordsFrequency;
}


function  format( wordsFrequency) {
    let result = '';
    for(var i = 0,len =  wordsFrequency.length; i < len; i ++){
        if(i > 0){
            result += '\r\n';
        }
        result = result +  wordsFrequency[i].word + ' ' +  wordsFrequency[i].count;
    }
    return result;
}

module.exports = {
    splitString : splitString,
    countFreqy : countFreqy,
    sortFrequency : sortFrequency,
    main: main
}


測(cè)試代碼如下


var frequencyNumber = require('./fn.js')
/*describe('split String to words', function(){

        it('return null given null', function(){
            expect(frequencyNumber.splitString('')).toEqual('');
        });

        it('return one word given one word ', function(){
            expect(frequencyNumber.splitString('it')).toEqual(['it']);
        });

        it('return two word given two word', function(){
            expect(frequencyNumber.splitString('it will')).toEqual(['it','will']);
        });

        it('return three word given three word ', function(){
            expect(frequencyNumber.splitString('it will get')).toEqual(['it', 'will', 'get']);
        });

        it('return two word given two word with some blanks', function(){
            expect(frequencyNumber.splitString('   it  will  ')).toEqual(['it','will']);
        });
    }
);

describe('count the Frequency of words',function () {

    it ('return one word and its frequency given one word', function () {
        expect(frequencyNumber.countFreqy(['it'])).toEqual("it 1");
    });

   it ('return two word and their own frequency given two different word', function () {
        expect(frequencyNumber.countFreqy(['it','is'])).toEqual("it 1\r\nis 1");
    });

    it ('return one word and their own frequency given two same word', function () {
        expect(frequencyNumber.countFreqy(['it','it'])).toEqual("it 2");
    });

});

describe ('sort the Frequency of the words',function(){

    it('return the result in sequence given the random result',function(){
        expect(frequencyNumber.sortFrequency([{word: 'it',count : 2},{word:'will',count:1}])).toEqual("will 1\r\nit 2");
    });

    it('return the result in sequence given the random result',function(){
        expect(frequencyNumber.sortFrequency([{word: 'it',count : 3},{word:'will',count:2},{word:'is', count: 1}])).toEqual("is 1\r\nwill 2\r\nit 3");
    });

});*/

describe('test for main',function(){
    it('return the result given the string ',function(){
        expect(frequencyNumber.main('it')).toEqual('it 1');
    });

    it('return the result given the string ',function(){
        expect(frequencyNumber.main('it will')).toEqual('it 1\r\nwill 1');
    });

    it('return the result given the string ',function(){
        expect(frequencyNumber.main('it will be it ')).toEqual('will 1\r\nbe 1\r\nit 2');
    });

    it('return the result given the string ',function(){
        expect(frequencyNumber.main('   it will it     ')).toEqual('will 1\r\nit 2');
    });
});

git log 截圖

git log

將項(xiàng)目 push 到 git 遠(yuǎn)程倉(cāng)庫(kù)

使用命令

$ git remote add origin https://github.com/chechenxm/FrequencyNumber.git
$ git push -u origin master

git項(xiàng)目地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鹿蜀,一起剝皮案震驚了整個(gè)濱河市茴恰,隨后出現(xiàn)的幾起案子斩熊,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異去件,居然都是意外死亡尤溜,警方通過查閱死者的電腦和手機(jī)宫莱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绝葡,“玉大人藏畅,你說我怎么就攤上這事愉阎。” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵澡屡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我室埋,道長(zhǎng)姚淆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任上忍,我火速辦了婚禮,結(jié)果婚禮上繁成,老公的妹妹穿的比我還像新娘巾腕。我一直安慰自己尊搬,他們只是感情好佛寿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布蜡饵。 她就那樣靜靜地躺著溯祸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胆绊。 梳的紋絲不亂的頭發(fā)上仆抵,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音娱两,去河邊找鬼十兢。 笑死遥缕,一個(gè)胖子當(dāng)著我的面吹牛宵呛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逮矛,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼堪藐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼挑围!你這毒婦竟也來了糖荒?” 一聲冷哼從身側(cè)響起捶朵,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤综看,失蹤者是張志新(化名)和其女友劉穎红碑,沒想到半個(gè)月后析珊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忠寻,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年柿顶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺鸥。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖笆载,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情复罐,我是刑警寧澤效诅,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站戚炫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏层宫。R本人自食惡果不足惜萌腿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一毁菱、第九天 我趴在偏房一處隱蔽的房頂上張望峦筒。 院中可真熱鬧窗慎,春花似錦遮斥、人聲如沸术吗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闸溃。三九已至辉川,卻和暖如春乓旗,著一層夾襖步出監(jiān)牢的瞬間屿愚,已是汗流浹背妆距。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留中剩,地道東北人结啼。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像井佑,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子红选,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容