如何从Array中删除empty / nil元素?

时间:2014-07-04 15:07:17

标签: delphi delphi-xe6

如何从数组中使用nil指针删除空元素或元素?欢迎使用通用解决方案。

1 个答案:

答案 0 :(得分:3)

你可以这样写:

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;

正如您所看到的,分析起来要困难得多。如果原始版本是瓶颈,你只会考虑这样做。