## Contents: Chronological Listing Of Exercises

### July 2, 2010

Although Scheme is a great language for the algorithmic exercises that we usually examine, I wrote this program in Awk, because of its good support for text munging:

`export PRAXIS=/home/phil/praxis`

``` awk ' # exercises in chronological order (page "chron") BEGIN { itemsperpage = 30; FS = "\n"; RS = ""         split("Jan:Feb:Mar:Apr:May:Jun:Jul:Aug:Sep:Oct:Nov:Dec",               monthname, ":") } \$1 ~ /^number\t[1-9][0-9]*\$/ {     for (i=1; i<=NF; i++)         if (split(\$i, f, /\t/) == 2)             val[f[1]] = f[2]     out[++nitems] = \     sprintf("<tr><td>%d</td><td>%02d %s %d</td>" \             "<td><a href=\"/%d/%02d/%02d/%s/\">%s</a>: %s</td>" \             "<td><a href=\"/%d/%02d/%02d/%s/\">exercise</a> " \             "<a href=\"/%d/%02d/%02d/%s/%d/\">solution</a> " \             "<a href=\"http://programmingpraxis.codepad.org/" \             "%s\">codepad</a></td></tr>",             val["number"], val["pubday"], monthname[val["pubmon"]],             val["pubyear"], val["pubyear"], val["pubmon"],             val["pubday"], val["file"], val["title"],             val["blurb"], val["pubyear"], val["pubmon"],             val["pubday"], val["file"], val["pubyear"],             val["pubmon"], val["pubday"], val["file"],             val["soln"], val["codepad"]) } # END { for (i=1; i<=nitems; i++) { #           if (i % itemsperpage == 1) #               printheader(i, nitems) #           print ""; print out[i] #           if (i % itemsperpage == 0 || i == nitems) #               printfooter(i, nitems) #           if (i % itemsperpage == 0 && i != nitems) #               printseparator(i, nitems) } } END { print "<table cellpadding=\"10\">"       for (i=1; i<=nitems; i++) {           print ""; print out[i] }       print "</table>" } function ceiling(n) { if (int(n) == n) return n; else return int(n) + 1 } function printheader(i, nitems) {     printf("%s", "<big><big>Page:&nbsp;")     for (page=1; page<=ceiling(nitems/itemsperpage); page++) {         if (ceiling(i/itemsperpage) == page) printf("&nbsp;%d", page)         else printf("&nbsp;<a href=\"/chron/%d\">%d</a>", page, page) }     print "</big></big>"; print ""; print "<table>" } function printfooter(i, nitems) { print ""; print "</table>" } function printseparator(i, nitems) { print ""; print "<!--nextpage-->\n" } ```

`' \$PRAXIS/praxis.info > \$PRAXIS/pages/chron`

The `BEGIN` action does some needed initialization. The main loop takes every record (maximal sequence of non-blank lines) beginning with the regular expression `^number\t[1-9][0-9]*\$`, splits the lines into name/value pairs stored in the `val` associative array, then builds an output line and stores it in the `out` associative array, incrementing the `nitems` variable as it does so. The `END` action writes the table header, the output lines in order, and the table footer. The program that creates the list of exercises in reverse chronological order is the same, except that the `END` action counts the `i` variable down from `nitems` to 1; it is not shown here.

Originally, I intended to put page breaks every thirty exercises, as in the original Contents page, but I decided instead to just put the entire listing on a single page, which is more convenient; after seeing the size of the permuted table of contents, it no longer seemed to matter that the chronological listing was too long. But I left the code to do that in the program source text, commented out, in case I change my mind some time in the future.

The code is available at http://programmingpraxis.codepad.org/KpvDEPnn.

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

```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>\
(g "number") (g "pubday") (toMonth . read \$ g "pubmon") (g "pubyear")
where g x = maybe "" last \$ find ((== x) . head) xs
link :: String -> String -> String
(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
```