В программировании на Delphi и Pascal часто возникает необходимость работы с массивами, включая операции добавления, изменения и удаления элементов. В этой статье мы рассмотрим проблему корректного удаления элементов из массива без искажения последующих вычислений, таких как расчет среднего значения.
Проблема удаления элементов из массива
Как правильно заметил автор вопроса, простое присвоение нулевого значения элементу массива не является настоящим удалением. Это приводит к проблемам при вычислении среднего значения, так как нуль учитывается как валидное значение, хотя должен быть исключен из расчетов.
Рассмотрим исходный код процедуры:
Procedure ModifierSupprimerMesure;
Var
jour, param: Integer;
choix: Char;
Begin
Writeln('--- Modifier ou Supprimer une Mesure ---');
Repeat
Write('Entrez le numéro du jour (1 à ', Nbre_J, ') : ');
read(jour);
Until (jour >= 1) And (jour <= Nbre_J);
Repeat
Writeln('1. Pression systolique');
Writeln('2. Pression diastolique');
Writeln('3. Pouls');
Write('Choisissez le paramètre à modifier/supprimer (1-3) : ');
read(param);
Until (param >= 1) And (param <= Max_Param);
Repeat
Write('Voulez-vous (M)odifier ou (S)upprimer la mesure ? (M/S) : ');
read(choix);
choix := Upcase(choix);
If (choix<>'M')Or(choix<>'S') Then Writeln('choix erroné');
Until (choix = 'M') Or (choix = 'S');
If choix = 'M' Then
Begin
Write('Entrez la nouvelle valeur : ');
read(Mesures[jour, param]);
End
Else
Begin
Mesures[jour, param] := 0;
End;
End;
Решение 1: Использование динамических массивов
Один из способов решения проблемы - использование динамических массивов и их перераспределение при удалении элемента:
procedure DeleteArrayElement(var Arr: array of Integer; Index: Integer);
var
i: Integer;
begin
if (Index < Low(Arr)) or (Index > High(Arr)) then Exit;
for i := Index to High(Arr) - 1 do
Arr[i] := Arr[i + 1];
SetLength(Arr, Length(Arr) - 1);
end;
Однако этот метод имеет недостатки: - Требует частого перераспределения памяти - Неэффективен для больших массивов - Усложняет код при работе с многомерными массивами
Решение 2: Использование флага для "удаленных" элементов
Более практичное решение - введение дополнительного массива флагов, указывающих на активность элементов:
var
Mesures: array[1..MaxDays, 1..MaxParams] of Integer;
ActiveFlags: array[1..MaxDays, 1..MaxParams] of Boolean;
procedure InitializeArrays;
var
i, j: Integer;
begin
for i := 1 to MaxDays do
for j := 1 to MaxParams do
ActiveFlags[i, j] := True;
end;
procedure DeleteMeasurement(Day, Param: Integer);
begin
ActiveFlags[Day, Param] := False;
end;
function CalculateAverage(Param: Integer): Double;
var
i, Count: Integer;
Sum: Double;
begin
Sum := 0;
Count := 0;
for i := 1 to MaxDays do
if ActiveFlags[i, Param] then
begin
Sum := Sum + Mesures[i, Param];
Inc(Count);
end;
if Count > 0 then
Result := Sum / Count
else
Result := 0;
end;
Решение 3: Использование списков вместо массивов
Для более гибкой работы с данными можно использовать классы TList или TObjectList:
uses
Classes, Contnrs;
type
TMeasurement = class
public
Day: Integer;
Systolic: Integer;
Diastolic: Integer;
Pulse: Integer;
constructor Create(ADay, ASystolic, ADiastolic, APulse: Integer);
end;
constructor TMeasurement.Create(ADay, ASystolic, ADiastolic, APulse: Integer);
begin
inherited Create;
Day := ADay;
Systolic := ASystolic;
Diastolic := ADiastolic;
Pulse := APulse;
end;
var
Measurements: TObjectList;
procedure InitializeMeasurements;
begin
Measurements := TObjectList.Create(True);
// Добавление измерений
Measurements.Add(TMeasurement.Create(1, 120, 80, 70));
// ...
end;
procedure DeleteMeasurement(Day: Integer);
var
i: Integer;
begin
for i := Measurements.Count - 1 downto 0 do
if TMeasurement(Measurements[i]).Day = Day then
Measurements.Delete(i);
end;
function CalculateAverage(ParamType: Integer): Double;
var
i, Count: Integer;
Sum: Double;
M: TMeasurement;
begin
Sum := 0;
Count := 0;
for i := 0 to Measurements.Count - 1 do
begin
M := TMeasurement(Measurements[i]);
case ParamType of
1: begin Sum := Sum + M.Systolic; Inc(Count); end;
2: begin Sum := Sum + M.Diastolic; Inc(Count); end;
3: begin Sum := Sum + M.Pulse; Inc(Count); end;
end;
end;
if Count > 0 then
Result := Sum / Count
else
Result := 0;
end;
Решение 4: Использование записей с дополнительными полями
Можно расширить структуру данных, добавив поле для отметки удаленных элементов:
type
TMeasurement = record
Value: Integer;
IsActive: Boolean;
end;
var
Mesures: array[1..MaxDays, 1..MaxParams] of TMeasurement;
procedure DeleteMeasurement(Day, Param: Integer);
begin
Mesures[Day, Param].IsActive := False;
end;
function CalculateAverage(Param: Integer): Double;
var
i, Count: Integer;
Sum: Double;
begin
Sum := 0;
Count := 0;
for i := 1 to MaxDays do
if Mesures[i, Param].IsActive then
begin
Sum := Sum + Mesures[i, Param].Value;
Inc(Count);
end;
if Count > 0 then
Result := Sum / Count
else
Result := 0;
end;
Заключение
В стандартном Pascal и Delphi статические массивы имеют фиксированный размер, и прямое удаление элементов невозможно. Однако существует несколько подходов к решению этой проблемы:
Использование динамических массивов с перераспределением памяти
Введение флагов активности элементов
Применение специализированных классов коллекций (TList, TObjectList)
Расширение структуры данных дополнительными полями
Для большинства практических задач оптимальным решением будет использование подхода с флагами активности (Решение 2) или переход на списки (Решение 3), так как они обеспечивают хороший баланс между производительностью и простотой реализации.
Выбор конкретного метода зависит от требований вашего приложения, частоты операций удаления и необходимости в других операциях с коллекцией данных.
В статье рассматриваются различные подходы к удалению элементов из массива в Delphi и Pascal, чтобы избежать искажения результатов вычислений, таких как среднее значение.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.