typestar

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

  1. Bump scans Words for a match, doing Inc(Counts[I]) or appending a new pair with SetLength.
  2. Tally walks the text keeping ['a'..'z', 'A'..'Z'] and lowercasing, flushing Token at each break.
  3. A selection sort pulls the largest Counts[Best] forward, then rows print bars via StringOfChar.

Keywords and builtins used here

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.

Type this snippet

Step 1 of 3 in Encore, step 25 of 27 in Language basics.

← Previous Next →