實用範例: 統計加總


lastlog.txt 資料檔讀入資料:

fs = require('fs') # 這句僅適用於 nodejs
lastLog = fs.readFileSync('lastlog.txt', 'utf8').split('\n')
lastLog.length
lastLog[50]
lastLog[50].match(/^(\w+)/)[1]
lastLog.map(function (x) { return x.match(/^(\w+)/)[1]; }) # 為何有錯誤訊息?
lastLog.length
lastLog = lastLog.filter(function (x) { return x.match(/^(\w+)/); })
lastLog.length
lastLog = lastLog.map(function (x) { return x.match(/^(\w+)/)[1]; })
# 再來一次就成功了; 也把它存起來

第一階段目標是想要先建立這樣的資料結構:

> raw
[ { id: 'm9426034',
    hour: '00',
    min: '02' },
  { id: 'm9426034',
    hour: '00',
    min: '04' },
  { id: 'm9426034',
    hour: '00',
    min: '01' },
  { id: 'm9426027',
    hour: '00',
    min: '38' },
  ...
  { id: 'm9426046',
    hour: '01',
    min: '06' },
  { id: 'm9426018',
    hour: '01',
    min: '49' },
  { id: 'm9426029',
    hour: '00',
    min: '02' } ]

這個用一句 map 就完成了: raw = lastLog.map(function (x) { m=x.match(/^(\w+).*\((\d\d):(\d\d)\)/); return {'id':m[1],'hour':m[2],'min':m[3]} } )

第二階段的目標是想要建立這樣的資料結構:

> stat
{ m9426034: { freq: 12, time: 394 },
  m9426027: { freq: 24, time: 476 },
  m9426009: { freq: 5, time: 310 },
  m9426020: { freq: 7, time: 354 },
  ...
  m9426031: { freq: 11, time: 272 },
  m9426028: { freq: 9, time: 214 },
  m9426005: { freq: 4, time: 229 } }

先練習一下如何操作 hash:

stat = {}
stat['greg'] = { 'freq':1, 'time':173 }
++stat['greg']['freq']; stat['greg']['time']+=94
'greg' in stat
'abc' in stat

所以可以這樣產生 stat:

stat = {}
raw.forEach(function (x) { id=x['id']; t=parseInt(x['hour'])*60+parseInt(x['min']); if (id in stat) { ++stat[id]['freq']; stat[id]['time']+=t; } else { stat[id] = { 'freq':1, 'time':t }; } } )

但是 hash 不方便排序; 陣列則有現成的函數可以排序。 所以想要把 stat 這個 hash 轉成 stat2 這樣的陣列:

> stat2
[ { id: 'm9426007',
    freq: 6,
    time: 72 },
  { id: 'm9426013',
    freq: 6,
    time: 149 },
  { id: 'm9426033',
    freq: 6,
    time: 154 },
  { id: 'm9426028',
    freq: 9,
    time: 214 },
  ...
  { id: 'm9426046',
    freq: 21,
    time: 1172 },
  { id: 'm9426002',
    freq: 10,
    time: 1604 },
  { id: 'm9426040',
    freq: 24,
    time: 1831 } ]

這也是用一個迴圈就可以完成。 要如何對 stat 這個 hash 裡面的每個元素做一些事呢? 用 for (k in stat) { ... } 在迴圈裡面, k 每次會變成 stat 的一個 key。

stat2 = []
for (k in stat) { stat2.push({'id':k,'freq':stat[k]['freq'],'time':stat[k]['time']}); }

最後, 就可以對 stat2 這個陣列按照 freq 或按照 time 來排序了:

stat2.sort(function(a,b){return a['freq']-b['freq'];})
stat2.sort(function(a,b){return b['freq']-a['freq'];})
stat2.sort(function(a,b){return a['time']-b['time'];})
stat2.sort(function(a,b){return b['time']-a['time'];})