word_freq.pas in Delphi
Counts words in an inline passage and prints the five most common with bars.
program WordFreq;
uses SysUtils;
const
Passage = 'The rain in Maine falls mainly on the plain, and the ' +
'plain is where the rain in Maine stays. Rain, rain!';
TopN = 5;
var
Words: array of string;
Counts: array of Integer;
// Add one to a word's tally, appending it the first time it shows up.
procedure Bump(const Item: string);
var
I: Integer;
begin
for I := 0 to High(Words) do
if Words[I] = Item then
begin
Inc(Counts[I]);
Exit;
end;
SetLength(Words, Length(Words) + 1);
SetLength(Counts, Length(Counts) + 1);
Words[High(Words)] := Item;
Counts[High(Counts)] := 1;
end;
// Split on anything that is not a letter, folding case along the way.
procedure Tally(const Text: string);
var
I: Integer;
Token: string;
begin
Token := '';
for I := 1 to Length(Text) + 1 do
if (I <= Length(Text)) and (Text[I] in ['a'..'z', 'A'..'Z']) then
Token := Token + LowerCase(Text[I])
else if Token <> '' then
begin
Bump(Token); // the extra step flushes the last word
Token := '';
end;
end;
var
I, J, Best, Swap: Integer;
Held: string;
begin
Tally(Passage);
// Selection sort: pull the largest remaining count to the front.
for I := 0 to High(Counts) - 1 do
begin
Best := I;
for J := I + 1 to High(Counts) do
if Counts[J] > Counts[Best] then
Best := J;
Swap := Counts[I]; Counts[I] := Counts[Best]; Counts[Best] := Swap;
Held := Words[I]; Words[I] := Words[Best]; Words[Best] := Held;
end;
WriteLn(Format('%d distinct words', [Length(Words)]));
WriteLn(Format('%-8s %5s %s', ['word', 'count', 'bar']));
for I := 0 to TopN - 1 do
WriteLn(Format('%-8s %5d %s',
[Words[I], Counts[I], StringOfChar('#', Counts[I])]));
end.
How it works
BumpscansWordsfor a match, doingInc(Counts[I])or appending a new pair withSetLength.Tallywalks the text keeping['a'..'z', 'A'..'Z']and lowercasing, flushingTokenat each break.- A selection sort pulls the largest
Counts[Best]forward, then rows print bars viaStringOfChar.
Keywords and builtins used here
BumpExitFormatHighIncIntegerLengthLowerCaseSetLengthStringOfCharSwapTallyWriteLnandarraybeginconstdoelseendforifinofprocedureprogramstringthentousesvar
The run, in numbers
- Lines
- 70
- Characters to type
- 1617
- Tokens
- 442
- Three-star pace
- 75 tpm
At the three-star pace of 75 tokens a minute, this run takes about 354 seconds.
Step 1 of 3 in Encore, step 25 of 27 in Language basics.