Главная

Подсчёт встречаемых значений

Оцените материал
(0 голосов)

Эта статья расскажет интересный способ правильного счёта количества встреченных значений в большинстве случаев. Например, будем искать, какие буквы алфавита встречаются в заданном заранее тексте и по сколько раз каждая.

var Txt: string;

Первое, что напрашивается у новичка, это обыкновенный подсчёт:

function Calc(bukva: char): string;
var i, k: integer;
begin
k := 0;
for i := 1 to length(Txt) do
if Txt[i] = bukva then k := k + 1;
Result := bukva + ': ' + IntToStr(k);
end;

Вызвать такую функцию можно так:

var c: char;

for c := 'A' to 'z' do Memo.Lines.Add(Calc(c));
for c := 'А' to 'я' do Memo.Lines.Add(Calc(c));
for c := '0' to '9' do Memo.Lines.Add(Calc(c));
Memo.Lines.Add(Calc(' '));

Но такой способ вынуждает нас "пробегать" по тексту заного для каждой буквы. Это ещё ничего, если ваш текст - несколько десятков символов, но при работе с большими текстами, скачиваемыми из файла, например, это будет занимать очень много времени.
Поэтому рассмотрим другой способ:
Как известно, каждый символ имеет свой код в системе ASCII. Функция Ord предназначена для того, чтобы получить такой код, а Chr - наоборот, возвращает символ по коду. Если эти функции Вам не знакомы, можете прочитать по ним справку, так как мы ими воспользуемся.
Создайте новый проект, на форму разместите два поля TMemo (одно для текста, другое для результата) и кнопку TButton
Для начала создадим глобальный массив:

var Bukavkes: array [32..255] of integer; // 32 - код пробела, до него идут только служебные символы


По правилам хорошего тона, в начале программы лучше его обнулить, так как существует вероятность, что его элементы при выделении памяти будут заполнены ненулевыми числами.
Сделаем это в событии формы OnCreate:

procedure TForm1.Form1Create(Sender: TObject);
var i: integer;
begin
for i := Low(Bukavkes) to High(Bukavkes) do Bukavkes[i] := 0;
Memo1.LoadFromFile('test.txt'); // можно загрузить текст из файла, либо набрать самому.
end;


Как видите, при создании формы мы обнуляем массив подсчётов букв и загружаем текст из любого текстового файла. Идеально подойдёт какая-нибудь большая книга, чтобы у Вас была возможность сравнить скорости каждого из способов.

В событии OnClick кнопки начнём вести подсчёт:
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
begin
for i := 1 to Memo1.Text do
if Ord(Memo1.Text[i]) >= 32 then inc(Bukavkes[Ord(Memo1.Text[i])]);
ShowResults(Memo2); // вызываем процедуру для вывода результатов
end;

В результате при встрече в тексте буквы "а" в массиве элемент с индексом Ord('a') увеличется на единицу. Аналогично произойдёт с другими буквами. Причём текст просматривался всего 1 раз!

На последок приведу код процедуры ShowResult (она должна находиться до Button1Click):
procedure ShowResults(Memo: TMemo);
begin
for i := Low(Bukavkes) to High(Bukavkes) do
if Chr(i) in ['A'..'z', 'А'..'я', '0'..'9', ' '] then // проверяем, является ли символ одним из наблюдаемых нами
Memo.Lines.Add(Chr(i) + ': ' + IntToStr(Bukavkes[i]));
end;

Вот, собственно, и весь код! Напоследок замечу, что данный метод можно применять в очень многих случаях. Например, подсчитывая распределение населения какой-либо местности по возрасту или другим данным.
Вот как может выглядеть массив для задачи подсчёта распределения по возрасту:

var Years: array[0..150] of integer;

Прочитано 75 раз

Авторизация



Счетчики