過去一時間で一番よく使ったコマンドは?

30分プログラム、その532。昨日のやつのリベンジ。
過去一時間で使ったコマンドの数を数えてみる。zshの場合、

$ history -i 1 | runghc freqCmd.hs
fc      18
history 8
cd      3
git     1
google  1
irssi   1
man     1

のようにしてやればいい。-iでYYYY/MM/DDl形式で時刻を表示させるのがポイント。

あと、interactが便利すぎる。

使い方

$ history -i 1 | runghc freqCmd.hs
fc      18
history 8
cd      3
git     1
google  1
irssi   1
man     1

ソースコード

import System.Locale
import Text.Printf
import Data.List
import Data.Time.Clock
import Data.Time.LocalTime
import qualified Data.Time.Format as Format
newtype History = History (UTCTime,String) deriving Show

-- parser
--   Example:
--   " 7249* 21.2.2009 20:27  google newtype haskell\n"
parse :: String -> History
parse xs = case split ' ' xs of
             _:date:time:cmd:_ ->
                 History (parseTime (date++time),cmd)
             _ ->
                 error "parse error"

parseTime :: String -> UTCTime
parseTime = Format.readTime defaultTimeLocale "%Y-%m-%d %H:%M"

split :: Eq a => a -> [a] -> [[a]]
split _ [] = []
split x xs = let (ys,zs) = break (==x) xs
             in if ys == [] then
                    split x $ dropWhile (==x) zs
                else
                    ys : split x (dropWhile (==x) zs)

-- selector
selectRecent :: UTCTime -> [History] -> [History]
selectRecent now xs = filter (\(History (t,_)) -> now `diffUTCTime` t < 60*60) xs

-- count
countByCmd :: [History] -> [(String,Int)]
countByCmd xs = sortBy (\(_,a) (_,b) -> compare b a) $
                 map (\x->(head x,length x))$ group $ sort ys
    where ys = map (\(History (_,c))->c) xs

-- format
format :: [(String,Int)] -> String
format = unlines.map (\(cmd,n)-> cmd ++ "\t"++ show n)

main = do now <- getCurrentTime
          interact (format.countByCmd.selectRecent now.map parse.lines)