4 ms·
Yeah the comparison between the shell script and the Pascal/LP version is a little bit apples/oranges. Maybe a nice counter to that would have been to make an L
by smcl 5y ago
Yeah the comparison between the shell script and the Pascal/LP version is a little bit apples/oranges. Maybe a nice counter to that would have been to make an LP version of the script itself. Here's a quickly hacked together mashup of the Knuth/McIlroy solutions:
Given some text input via stdin, we want to find the word that appears most often. The main body of the shell script is as follows - each section uses plain shell utilities and has been developed and tested with (blah blah, maybe mention the version of the utils we used in case GNU versions work but BSD don't or something)
<<makeLines>> | <<convertToLowerCase>> | <<sortAndCountLines>> | <<sortLinesByFrequency>> | <<takeFirst>>
The first job is to isolate "words", defined here as groups of lower case latin alphabet characters (sorry to our international friends out there!) using `tr`. Importantly anything hyphenated will be treated as a separate words ("short-term" will be "short" and "term", for example), so modify the pattern if this isn't what you need.
<<makeLines>> = tr -cs A-Za-z '\n'
Next we'll make everything in the input lower-case:
<<convertToLowerCase>> = tr A-Z a-z
The next step is to sort the lines so exact words are next to each other, then pipe that into `uniq -c` to get counts for each adjacent line. This is a fairly common pattern so I've bunched these guys together.
<<sortAlphabeticallyAndCount>> = sort | uniq -c
Since we're interested in the most frequent we're sorting descending (-r aka --reverse. IMPORTANT: not -R aka --random-sort) and numerically (-n)
<<sortNumerically>> = sort -rn
And finally we can take the first line and print it. NOTE: I didn't use `head -n 1` here because blah stupid reason whatever
<<takeFirst>> = sed ${1}q
(fin)
This is the first time I'd ever written anything approaching LP (I just copied the style in the article) so I just quickly dashed it out with placeholder comments, though I'd maybe include a worked example of the program in action too showing the output at each step. Now obviously it's longer than the little shell snippet that was posted, but even though it is a relatively tiny problem to apply LP to, you can see that there is still some value to it - I've been able to make it clear that only the latin alphabet is considered, I've highlighted a potential oopsie in case someone inexperienced in tries to re-use it (-r/-R), I was able to state that there's an alternative approach to the final step and give a reason why I chose my way.
- thyrsus 5y agoIn shell (/bin/sh) ${1} gives you the first argument, which for simplicity in this context is trusted to be an integer, e.g., if the shell script name is most_freq_words, "most_freq_words 5" would put the five most frequent words, one per line, on stdout. If you want to use head instead of sed, you'd say "head ${1}"
- smcl 5y agoGood catch, I wasn't very thorough I just wanted to show what it might look like - also I mangled a couple of the step names :)