Contents: Chronological Listing Of Exercises

July 2, 2010

You may have noticed that the Contents page changed recently. Previously the Contents page listed all the exercises in chronological order. Now, there are four listings of the exercises, in chronological order, reverse chronological order, permuted by the words in the title and summary, and organized manually by themes.

The four listings all derive from a single source. The file praxis.info consists of records separated by blank lines, fields on a single line with field name followed by a tab character followed by the data element. Here is an excerpt, which shows the header at the beginning of the file followed by the first two records:

praxis.info

number  exercise number
file    base name of files
pubmon  month of publication
pubday  day of publication
pubyear year of publication
title   formatted title
ptitle  plain title
blurb   formatted blurb
pblurb  plain blurb
exer    exercise sub-page number
soln    solution sub-page number
extra   extra info sub-page number
codepad eight-character codepad index
theme   category in which exercise appears

name/value pairs on a line separated by tabs,
with records separated by blank lines

the "number" field must appear first, others
may be in any order, and are optional

----+----1----+----2----+----3----+----4----+----5----+----6

number  1
file    rpn-calculator
pubmon  2
pubday  19
pubyear 2009
title   RPN Calculator
blurb   Evaluate numeric expressions at the command line
exer    1
soln    2
codepad fjzlC50x
theme   Parsing

number  2
file    sieve-of-eratosthenes
pubmon  2
pubday  19
pubyear 2009
title   Sieve of Eratosthenes
blurb   A Scheme implementation of an ancient algorithm
exer    1
soln    2
codepad wI14BJ8Q
theme   Prime Numbers

Four programs manipulate the data from the praxis.info file to produce the four listings. The output has elements of html, but WordPress adds the surrounding context; here is the corresponding excerpt from the listing in chronological order:

<table cellpadding="10">

<tr><td>1</td><td>19 Feb 2009</td><td><a href="/2009/02/19/rpn-calculator/">RPN Calculator</a>: Evaluate numeric expressions at the command line</td><td><a href="/2009/02/19/rpn-calculator/">exercise</a> <a href="/2009/02/19/rpn-calculator/2/">solution</a> <a href="http://programmingpraxis.codepad.org/fjzlC50x">codepad</a></td></tr>

<tr><td>2</td><td>19 Feb 2009</td><td><a href="/2009/02/19/sieve-of-eratosthenes/">Sieve of Eratosthenes</a>: A Scheme implementation of an ancient algorithm</td><td><a href="/2009/02/19/sieve-of-eratosthenes/">exercise</a> <a href="/2009/02/19/sieve-of-eratosthenes/2/">solution</a> <a href="http://programmingpraxis.codepad.org/wI14BJ8Q">codepad</a></td></tr>

</table>

Your task is to write programs that read praxis.info and write the two listing files for exercises in chronological order and reverse chronological order. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

2 Responses to “Contents: Chronological Listing Of Exercises”

  1. […] Praxis – Chronological Listing Of Exercises By Remco Niemeijer In today’s Programming Praxis exercise our goal is to replicate a script Phil wrote to generate chronological […]

  2. Remco Niemeijer said

    My Haskell solution (see http://bonsaicode.wordpress.com/2010/07/02/programming-praxis-chronological-listing-of-exercises/ for a version with comments):

    import Data.List
    import Data.List.Split
    import Text.Printf
    import Text.Regex.Posix
    
    toMonth :: Int -> String
    toMonth m = chunk 3 "JanFebMarAprMayJunJulAugSepOctNovDec" !! (m - 1)
    
    item :: [[String]] -> String
    item xs = printf
        "<tr><td>%s</td><td>%02s %s %s</td><td>%s: %s</td>\
        \<td>%s%s<a href=\"http://programmingpraxis.codepad.org/%s\">\
        \codepad</a></td></tr>"
        (g "number") (g "pubday") (toMonth . read $ g "pubmon") (g "pubyear")
        (link "" (g "title")) (g "blurb") (link "" "exercise")
        (link ("/" ++ g "soln") "solution") (g "codepad")
        where g x = maybe "" last $ find ((== x) . head) xs
              link :: String -> String -> String
              link = printf "<a href=\"/%s/%02s/%02s/%s%s/\">%s</a>"
                     (g "pubyear") (g "pubmon") (g "pubday") (g "file")
    
    items :: String -> [String]
    items = map (item . map (splitOn "\t") . lines) .
            filter (=~ "^number\t[1-9][0-9]*$") . splitOn "\n\n"
    
    listing :: ([String] -> [String]) -> String -> String
    listing f xs = "<table cellpadding=\"10\">" ++ 
                   concat (f $ items xs) ++ "</table>"
    
    main :: IO ()
    main = do x <- readFile "praxis.info"
              putStrLn $ listing id x
              putStrLn $ listing reverse x
    

Leave a comment