Another Haskell Solution to Lars’ Problem

September 5th, 2006

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.

Categories: Programming

Tags: Leave a comment

Comments Feed3 Comments

  1. Tom Moertel

    Is there a reason you didn’t define [i]updmap[/i] to use [i]Map.insertWith[/i]?:

    [code]updmap nm key = Map.insertWith (+) key 1 nm[/code]

    Was it because you needed the force the addition to be evaluated strictly?

    Cheers,
    Tom

    Reply

    John Goerzen Reply:

    Yes, that was exactly it. I had originally written it your way, in fact, and changed it due to insertWith.

    Reply

  2. Antti-Juhani Kaijanaho

    Note that you don’t use entities for et, lt and gt. You should. I suspect this is the reason planet “corrupts” the code.

    (Yes, entities are required even in pre.)

    Reply

Leave a comment

 

Feed

http://changelog.complete.org / Another Haskell Solution to Lars’ Problem