Как удалить пустые / нулевые элементы из массива?
Как я могу удалить пустые элементы или элементы с нулевыми указателями из массива? Общее решение будет приветствоваться.
1 ответ
Вы можете написать это так:
type
TArrayHelper = class
class function RemoveAll<T>(var Values: TArray<T>; const Value: T); static;
end;
....
function TArrayHelper.RemoveAll<T>(var Values: TArray<T>; const Value: T);
var
Index, Count: Integer;
DefaultComparer: IEqualityComparer<T>;
begin
// obtain an equality comparer for our type T
DefaultComparer := TEqualityComparer<T>.Default;
// loop over the the array, only retaining non-matching values
Count := 0;
for Index := 0 to high(Values) do begin
if not DefaultComparer.Equals(Values[Index], Value) then begin
Values[Count] := Values[Index];
inc(Count);
end;
end;
// re-size the array
SetLength(Values, Count);
end;
Предположим, что у вас есть массив указателей:
var
arr: TArray<Pointer>;
Тогда вы бы удалили nil
элементы как это:
TArrayHelper.RemoveAll<Pointer>(arr, nil);
Этот код выбирает легкий путь и всегда использует компаратор по умолчанию. Для более сложных типов это не хорошо. Например, некоторые записи нуждаются в пользовательских компараторах. Вы должны были бы предоставить компаратор, чтобы поддержать это.
Вышеуказанная реализация максимально проста. С точки зрения производительности, это может быть расточительным в вероятном общем сценарии, когда не найдено ни одного подходящего значения, или очень мало. Это потому, что версия выше безоговорочно присваивает, даже если два индекса одинаковы.
Вместо этого, если возникла проблема с производительностью, вы могли бы оптимизировать код, шагая по массиву до первого совпадения. И только тогда начнут двигаться значения.
function TArrayHelper.RemoveAll<T>(var Values: TArray<T>; const Value: T);
var
Index, Count: Integer;
DefaultComparer: IEqualityComparer<T>;
begin
// obtain an equality comparer for our type T
DefaultComparer := TEqualityComparer<T>.Default;
// step through the array until we find a match, or reach the end
Count := 0;
while (Count<=high(Values))
and not DefaultComparer.Equals(Values[Count], Value) do begin
inc(Count);
end;
// Count is either the index of the first match or one off the end
// loop over the rest of the array copying non-matching values to the next slot
for Index := Count to high(Values) do begin
if not DefaultComparer.Equals(Values[Index], Value) then begin
Values[Count] := Values[Index];
inc(Count);
end;
end;
// re-size the array
SetLength(Values, Count);
end;
Как видите, это гораздо сложнее анализировать. Вы бы только могли подумать о том, чтобы сделать это, если бы оригинальная версия была узким местом.