Yesterday, I posted an 18-line solution to Lars’ language problem. One problem with it was that it was not very memory-efficient (or time-efficient, for that matter). In other words, it was optimized for elegance.
Here is a 22-line solution that is much more memory-efficient and works well with his “huge” test case. Note to Planet readers: Planet seems to corrupt code examples at times; click on the original story to see the correct code.
import System.Environment import Data.List import Data.Char import qualified Data.Map as Map custwords = filter (/= "") . lines . map (conv . toLower) where iswordchar x = isAlphaNum x && isAscii x conv x = if iswordchar x then x else '\n' wordfreq inp = Map.toList $ foldl' updmap (Map.empty::Map.Map String Int) inp where updmap nm word = case Map.lookup word nm of Nothing -> Map.insert word 1 nm Just x -> (Map.insert word $! x + 1) nm freqsort (w1, c1) (w2, c2) = if c1 == c2 then compare w1 w2 else compare c2 c1 showit (word, count) = show count ++ " " ++ word main = do args <- getArgs interact $ unlines . map showit . take (read . head $ args) . sortBy freqsort . wordfreq . custwords
The main change from the previous example to this one is using a Map to keep track of the frequency of each word.