频道分类

Delphi泛型动态数组的扩展,归属 武稀松 所有!

作者:admin 来源: 日期:2018/3/14 8:33:34 人气: 标签:

 
武稀松真的是Delphi 界里的一个大银才,他写的博客文章非常新颖和实用,如今竟然将泛型数组封装的如此有声有色。
我对这个泛型动态数组的扩展爱不释手,在他开源的代码上,增加了排序和搜索两个小功能,纯属搬运和投机取巧!
特此声明,源码版权和解释权归属 武稀松 所有。

var
  //声明动态数组
  a, b, c: TArrayEx<Integer>;
  f: TArrayEx<Single>;
  s : TArrayEx<string>;
  //
  i: Integer;
  z: array of Integer;
  args:TArrayEx<string>;
begin
  // 直接给数组分配内容
  a := [2, 2, 3, 4];
  s := ['haha', 'hello'];
  // 克隆
  b := a.Clone;
 
  // 给元素赋值
  b[0] := 5;
 
  // 操作符重载,两个数组相加或给数组加元素
  c := a + b;
 
  c := 88 + c + 99;
  a.Append([10, 20, 30]);
  a.Insert(2, 1000);
  a.Insert(2, [1000, 45]);
 
  a[0] := 7;
  // 去重
  c.Unique;
  // 删除
  c.Delete(0, 3);
  // 比较
  if c = z then
    // for in 循环
    for i in c do
      if i = 0 then
      begin
        //
      end;
  //
  f := [1, 2, 3.1415926];
  f.Size := 200;
  if f[0] = 1.0 then
  begin
 
  end;
 
  args := ['38寸','45寸','XL','XL2','X','38寸','45寸'];
  args.Unique;
  args.Sort;


  if args.BinarySearch('XL',i) then
    ShowMessageFmt('foud index:%d',[i]);
 
end;


unit ArrayEx;
{ ******************************************************************************
  泛型动态数组的扩展.
 
  wr960204 武稀松
  博客地址:
  http://www.raysoftware.cn/
 
  2013.6.4
  ****************************************************************************** }
interface
 uses System.Generics.Defaults,System.SysUtils;
 
type
  TArrayEx<T> = record
  strict private
  type
    TEnumerator = class
    private
      FValue: TArray<T>;
      FIndex: NativeInt;
      function GetCurrent: T;
    public
      constructor Create(const AValue: TArray<T>);
      function MoveNext: Boolean;
      property Current: T read GetCurrent;
    end;
  public
    function GetEnumerator(): TEnumerator;
  strict private
    FData: TArray<T>;
    function GetRawData: TArray<T>;
    function GetElements(Index: Integer): T;
    procedure SetElements(Index: Integer; const Value: T);
  private
    class function EqualArray(A, B: TArray<T>): Boolean; static;
    class function CompareT(const A, B: T): Boolean; static;
    class procedure CopyArray(var FromArray, ToArray: TArray<T>;
      FromIndex: NativeInt = 0; ToIndex: NativeInt = 0;
      Count: NativeInt = -1); static;
    class procedure MoveArray(var AArray: array of T;
      FromIndex, ToIndex, Count: Integer); static;
    class function DynArrayToTArray(const Value: array of T): TArray<T>; static;
    class function Min(A, B: NativeInt): NativeInt; static;
    procedure QuickSort(const Comparer: IComparer<T>;
      L, R: Integer);
  public // operators
    class operator Implicit(Value: TArray<T>): TArrayEx<T>; overload;
    class operator Implicit(Value: array of T): TArrayEx<T>; overload;
    (*
      这个无解,Delphi不允许array of T作为返回值.也就是这个转换是被废了.只好用AssignTo
      class operator Implicit(Value:  TArrayEx<T>):array of T; overload;
    *)
    class operator Implicit(Value: TArrayEx<T>): TArray<T>; overload;
    class operator Explicit(Value: TArrayEx<T>): TArray<T>; overload;
    class operator Explicit(Value: array of T): TArrayEx<T>; overload;
 
    class operator Add(A, B: TArrayEx<T>): TArrayEx<T>; overload;
    class operator Add(A: TArrayEx<T>; const B: T): TArrayEx<T>; overload;
    class operator Add(const A: T; B: TArrayEx<T>): TArrayEx<T>; overload;
    class operator Add(A: TArrayEx<T>; B: array of T): TArrayEx<T>; overload;
    class operator Add(A: array of T; B: TArrayEx<T>): TArrayEx<T>; overload;
    class operator In (A: T; B: TArrayEx<T>): Boolean; overload;
    //
    class operator Equal(A, B: TArrayEx<T>): Boolean; overload;
    class operator Equal(A: TArrayEx<T>; B: TArray<T>): Boolean; overload;
    class operator Equal(A: TArray<T>; B: TArrayEx<T>): Boolean; overload;
    class operator Equal(A: array of T; B: TArrayEx<T>): Boolean; overload;
    class operator Equal(A: TArrayEx<T>; B: array of T): Boolean; overload;
 
  public
    procedure SetLen(Value: NativeInt); inline;
    function GetLen: NativeInt; inline;
    function ByteLen: NativeInt; inline;
    class function Create(Value: array of T): TArrayEx<T>; overload; static;
    class function Create(Value: TArrayEx<T>): TArrayEx<T>; overload; static;
    class function Create(const Value: T): TArrayEx<T>; overload; static;
    function Clone(): TArrayEx<T>;
    procedure SetValue(Value: array of T);
    function ToArray(): TArray<T>;
    function SubArray(AFrom, ACount: NativeInt): TArrayEx<T>;
    procedure Delete(AFrom, ACount: NativeInt); overload;
    procedure Delete(AIndex: NativeInt); overload;
    procedure Append(Values: TArrayEx<T>); overload;
    procedure Append(const Value: T); overload;
    procedure Append(Values: array of T); overload;
    procedure Append(Values: TArray<T>); overload;
    function Insert(AIndex: NativeInt; const Value: T): NativeInt; overload;
    function Insert(AIndex: NativeInt; const Values: array of T)
      : NativeInt; overload;
    function Insert(AIndex: NativeInt; const Values: TArray<T>)
      : NativeInt; overload;
    function Insert(AIndex: NativeInt; const Values: TArrayEx<T>)
      : NativeInt; overload;
    procedure Unique();
    //排序
    procedure Sort(); overload;
    procedure Sort(const Comparer: IComparer<T>); overload;
    procedure Sort(const Comparer: IComparer<T>; Index, Count: Integer); overload;
    //搜索
    function BinarySearch(const Item: T;
      out FoundIndex: Integer; const Comparer: IComparer<T>;
      Index, Count: Integer): Boolean; overload;
    function BinarySearch(const Item: T;
      out FoundIndex: Integer; const Comparer: IComparer<T>): Boolean; overload;
    function BinarySearch(const Item: T;
      out FoundIndex: Integer): Boolean; overload;
 
    property Size: NativeInt read GetLen write SetLen;
    property Len: NativeInt read GetLen write SetLen;
    property RawData: TArray<T> read GetRawData;
    property Elements[Index: Integer]: T read GetElements
      write SetElements; default;
  end;
 
implementation
 uses System.RTLConsts;
 
class operator TArrayEx<T>.Add(A, B: TArrayEx<T>): TArrayEx<T>;
begin
  Result := A.Clone;
  Result.Append(B);
end;
 
class operator TArrayEx<T>.Add(A: TArrayEx<T>; const B: T): TArrayEx<T>;
begin
  Result := A.Clone;
  Result.Append(B);
end;
 
class operator TArrayEx<T>.Add(const A: T; B: TArrayEx<T>): TArrayEx<T>;
begin
  Result.SetValue([A]);
  Result.Append(B);
end;
 
class operator TArrayEx<T>.Add(A: TArrayEx<T>; B: array of T): TArrayEx<T>;
begin
  Result := A.Clone;
  Result.Append(B);
end;
 
class operator TArrayEx<T>.Add(A: array of T; B: TArrayEx<T>): TArrayEx<T>;
begin
  Result.FData := DynArrayToTArray(A);
  Result.Append(B);
end;
 
class operator TArrayEx<T>.In(A: T; B: TArrayEx<T>): Boolean;
var
  Tmp: T;
begin
  Result := False;
  for Tmp in B.FData do
    if CompareT(A, Tmp) then
    begin
      Result := True;
      Break;
    end;
end;
 
class operator TArrayEx<T>.Equal(A, B: TArrayEx<T>): Boolean;
begin
  Result := EqualArray(A.FData, B.FData);
end;
 
class operator TArrayEx<T>.Equal(A: TArrayEx<T>; B: TArray<T>): Boolean;
begin
  Result := EqualArray(A.FData, B);
end;
 
class operator TArrayEx<T>.Equal(A: TArray<T>; B: TArrayEx<T>): Boolean;
begin
  Result := EqualArray(A, B.FData);
end;
 
class operator TArrayEx<T>.Equal(A: array of T; B: TArrayEx<T>): Boolean;
begin
  Result := EqualArray(DynArrayToTArray(A), B.FData);
end;
 
class operator TArrayEx<T>.Equal(A: TArrayEx<T>; B: array of T): Boolean;
begin
  Result := EqualArray(A.FData, DynArrayToTArray(B));
end;
 
function TArrayEx<T>.BinarySearch(const Item: T; out FoundIndex: Integer;
  const Comparer: IComparer<T>; Index, Count: Integer): Boolean;
var
  L, H: Integer;
  mid, cmp: Integer;
begin
  if (Index < Low(FData)) or ((Index > High(FData)) and (Count > 0))
    or (Index + Count - 1 > High(FData)) or (Count < 0)
    or (Index + Count < 0) then
    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
  if Count = 0 then
  begin
    FoundIndex := Index;
    Exit(False);
  end;
 
  Result := False;
  L := Index;
  H := Index + Count - 1;
  while L <= H do
  begin
    mid := L + (H - L) shr 1;
    cmp := Comparer.Compare(FData[mid], Item);
    if cmp < 0 then
      L := mid + 1
    else
    begin
      H := mid - 1;
      if cmp = 0 then
        Result := True;
    end;
  end;
  FoundIndex := L;
end;
 
function TArrayEx<T>.BinarySearch(const Item: T; out FoundIndex: Integer;
  const Comparer: IComparer<T>): Boolean;
begin
  Result := BinarySearch(Item, FoundIndex, Comparer,
    Low(FData), Length(FData));
end;
 
function TArrayEx<T>.BinarySearch(const Item: T;
  out FoundIndex: Integer): Boolean;
begin
  Result := BinarySearch(Item, FoundIndex, TComparer<T>.Default,
    Low(FData), Length(FData));
end;
 
function TArrayEx<T>.ByteLen: NativeInt;
begin
  Result := Length(FData) * Sizeof(T);
end;
 
class function TArrayEx<T>.Min(A, B: NativeInt): NativeInt;
begin
  Result := A;
  if Result > B then
    Result := B;
end;
 
 
class procedure TArrayEx<T>.CopyArray(var FromArray, ToArray: TArray<T>;
  FromIndex, ToIndex, Count: NativeInt);
var
  i: Integer;
begin
  if Count = 0 then
    Exit;
  if Count < 0 then
    Count := Min(Length(FromArray), Length(ToArray));
  if Length(FromArray) < (FromIndex + Count) then
    Count := Length(FromArray) - FromIndex;
  if Length(ToArray) < (ToIndex + Count) then
    Count := Length(ToArray) - ToIndex;
 
  if Count > 0 then
    for i := 0 to Count - 1 do
      ToArray[ToIndex + i] := FromArray[FromIndex + i];
end;
 
class procedure TArrayEx<T>.MoveArray(var AArray: array of T;
  FromIndex, ToIndex, Count: Integer);
var
  i: Integer;
begin
  if Count > 0 then
  begin
    if FromIndex < ToIndex then
      for i := Count - 1 downto 0 do
        AArray[ToIndex + i] := AArray[FromIndex + i]
    else if FromIndex > ToIndex then
      for i := 0 to Count - 1 do
        AArray[ToIndex + i] := AArray[FromIndex + i];
  end;
end;
 
procedure TArrayEx<T>.QuickSort(const Comparer: IComparer<T>; L, R: Integer);
var
  I, J: Integer;
  pivot, temp: T;
begin
  if (Length(FData) = 0) or ((R - L) <= 0) then
    Exit;
  repeat
    I := L;
    J := R;
    pivot := FData[L + (R - L) shr 1];
    repeat
      while Comparer.Compare(FData[I], pivot) < 0 do
        Inc(I);
      while Comparer.Compare(FData[J], pivot) > 0 do
        Dec(J);
      if I <= J then
      begin
        if I <> J then
        begin
          temp := FData[I];
          FData[I] := FData[J];
          FData[J] := temp;
        end;
        Inc(I);
        Dec(J);
      end;
    until I > J;
    if L < J then
      QuickSort(Comparer, L, J);
    L := I;
  until I >= R;
end;
 
class function TArrayEx<T>.DynArrayToTArray(const Value: array of T): TArray<T>;
var
  i: Integer;
begin
  SetLength(Result, Length(Value));
  for i := Low(Value) to High(Value) do
    Result[i] := Value[i];
end;
 
class function TArrayEx<T>.EqualArray(A, B: TArray<T>): Boolean;
var
  i: Integer;
begin
  Result := True;
  if A = B then
    Exit;
  if Length(A) <> Length(B) then
  begin
    Result := False;
  end
  else
  begin
    for i := Low(A) to High(A) do
      if not CompareT(A[i], B[i]) then
      begin
        Result := False;
        Break;
      end;
  end;
end;
 
class function TArrayEx<T>.CompareT(const A, B: T): Boolean;
var
  Compare : IComparer<T>;
begin
  Compare := TComparer<T>.Default;
  Result := Compare.Compare(A, B) = 0;
end;
//class function TArrayEx<T>.CompareT(const A, B: T): Boolean;
//var
//  p1, p2: PByte;
//  i: Integer;
//begin
//  Result := True;
//  p1 := PByte(@A);
//  p2 := PByte(@B);
//  for i := 0 to Sizeof(T) - 1 do
//  begin
//    //
//    if p1^ <> p2^ then
//    begin
//      Result := False;
//      Exit;
//    end;
//    Inc(p1);
//    Inc(p2);
//  end;
//end;
 
function TArrayEx<T>.GetElements(Index: Integer): T;
begin
  Result := FData[Index];
end;
 
function TArrayEx<T>.GetEnumerator: TEnumerator;
begin
  Result := TEnumerator.Create(FData);
end;
 
function TArrayEx<T>.GetLen: NativeInt;
begin
  Result := Length(FData);
end;
 
function TArrayEx<T>.GetRawData: TArray<T>;
begin
  Result := FData;
end;
 
class operator TArrayEx<T>.Implicit(Value: TArrayEx<T>): TArray<T>;
begin
  SetLength(Result, Length(Value.FData));
  CopyArray(Value.FData, Result, 0, 0, Length(Value.FData));
end;
 
class operator TArrayEx<T>.Explicit(Value: array of T): TArrayEx<T>;
begin
  Result.SetValue(Value);
end;
 
class operator TArrayEx<T>.Implicit(Value: array of T): TArrayEx<T>;
begin
  Result.SetValue(Value);
end;
 
class operator TArrayEx<T>.Implicit(Value: TArray<T>): TArrayEx<T>;
begin
  SetLength(Result.FData, Length(Value));
  CopyArray(Value, Result.FData, 0, 0, Length(Value));
end;
 
class operator TArrayEx<T>.Explicit(Value: TArrayEx<T>): TArray<T>;
begin
  SetLength(Result, Length(Value.FData));
  CopyArray(Value.FData, Result, 0, 0, Length(Value.FData));
end;
 
procedure TArrayEx<T>.SetElements(Index: Integer; const Value: T);
begin
  FData[Index] := Value;
end;
 
procedure TArrayEx<T>.SetLen(Value: NativeInt);
begin
  SetLength(FData, Value);
end;
 
procedure TArrayEx<T>.SetValue(Value: array of T);
begin
  FData := DynArrayToTArray(Value);
end;
 
procedure TArrayEx<T>.Sort;
begin
  QuickSort(TComparer<T>.Default, Low(FData), High(FData));
end;
 
procedure TArrayEx<T>.Sort(const Comparer: IComparer<T>; Index, Count: Integer);
begin
  if (Index < Low(FData)) or ((Index > High(FData)) and (Count > 0))
    or (Index + Count - 1 > High(FData)) or (Count < 0)
    or (Index + Count < 0) then
    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
  if Count <= 1 then
    Exit;
  QuickSort(Comparer, Index, Index + Count - 1);
end;
 
procedure TArrayEx<T>.Sort(const Comparer: IComparer<T>);
begin
  QuickSort(Comparer, Low(FData), High(FData));
end;
 
function TArrayEx<T>.ToArray(): TArray<T>;
begin
  SetLength(Result, Length(FData));
  CopyArray(FData, Result, 0, 0, Length(FData));
end;
 
class function TArrayEx<T>.Create(Value: array of T): TArrayEx<T>;
begin
  Result.SetValue(Value);
end;
 
class function TArrayEx<T>.Create(Value: TArrayEx<T>): TArrayEx<T>;
begin
  Result := Value.Clone;
end;
 
class function TArrayEx<T>.Create(const Value: T): TArrayEx<T>;
begin
  Result.SetValue([Value]);
end;
 
function TArrayEx<T>.Clone(): TArrayEx<T>;
begin
  Result := SubArray(0, Length(FData));
end;
 
function TArrayEx<T>.SubArray(AFrom, ACount: NativeInt): TArrayEx<T>;
begin
  SetLength(Result.FData, ACount);
  CopyArray(FData, Result.FData, AFrom, 0, ACount);
end;
 
procedure TArrayEx<T>.Delete(AFrom, ACount: NativeInt);
begin
  if AFrom >= Length(FData) then
    Exit;
  if (AFrom + ACount) > Length(FData) then
    ACount := Length(FData) - AFrom;
 
  MoveArray(FData, AFrom + ACount, AFrom, Length(FData) - (AFrom + ACount));
  SetLength(FData, Length(FData) - ACount);
end;
 
procedure TArrayEx<T>.Delete(AIndex: NativeInt);
begin
  Delete(AIndex, 1);
end;
 
procedure TArrayEx<T>.Append(Values: TArrayEx<T>);
begin
  Insert(Length(FData), Values);
end;
 
procedure TArrayEx<T>.Append(Values: TArray<T>);
begin
  Insert(Length(FData), Values);
end;
 
procedure TArrayEx<T>.Append(const Value: T);
begin
  SetLength(FData, Length(FData) + 1);
  FData[High(FData)] := Value;
end;
 
procedure TArrayEx<T>.Append(Values: array of T);
begin
  Insert(Length(FData), Values);
end;
 
function TArrayEx<T>.Insert(AIndex: NativeInt; const Value: T): NativeInt;
var
  i: Integer;
begin
  Result := -1;
  if (AIndex > Length(FData)) or (AIndex < 0) then
    Exit;
  SetLength(FData, Length(FData) + 1);
  MoveArray(FData, AIndex, AIndex + 1, Length(FData) - AIndex);
  FData[AIndex] := Value;
  Result := AIndex;
end;
 
function TArrayEx<T>.Insert(AIndex: NativeInt; const Values: array of T)
  : NativeInt;
var
  i: Integer;
begin
  SetLength(FData, Length(Values));
  MoveArray(FData, AIndex, AIndex + Length(Values), Length(FData) - AIndex);
  for i := 0 to Length(Values) - 1 do
    FData[AIndex + i] := Values[i];
  Result := AIndex;
end;
 
function TArrayEx<T>.Insert(AIndex: NativeInt; const Values: TArray<T>)
  : NativeInt;
var
  i: Integer;
begin
  SetLength(FData, Length(FData) + Length(Values));
  MoveArray(FData, AIndex, AIndex + Length(Values), Length(FData) - AIndex);
  for i := 0 to Length(Values) - 1 do
    FData[AIndex + i] := Values[i];
  Result := AIndex;
end;
 
function TArrayEx<T>.Insert(AIndex: NativeInt; const Values: TArrayEx<T>)
  : NativeInt;
begin
  Result := Insert(AIndex, Values.ToArray);
end;
 
procedure TArrayEx<T>.Unique();
var
  i, J: Integer;
  Tmp: TArrayEx<T>;
  Flag: Boolean;
begin
 
  for i := High(FData) downto Low(FData) do
  begin
    Flag := False;
    for J := High(Tmp.FData) downto Low(Tmp.FData) do
    begin
      if CompareT(FData[i], Tmp[J]) then
      begin
        Flag := True;
        Break;
      end;
    end;
    if not Flag then
      Tmp.Append(FData[i]);
  end;
  FData := Tmp.FData;
end;
 
{ TArrayEx<T>.TEnumerator }
 
constructor TArrayEx<T>.TEnumerator.Create(const AValue: TArray<T>);
begin
  FValue := AValue;
  FIndex := -1;
end;
 
function TArrayEx<T>.TEnumerator.GetCurrent: T;
begin
  Result := FValue[FIndex];
end;
 
function TArrayEx<T>.TEnumerator.MoveNext: Boolean;
begin
  Result := False;
  if (FIndex >= Length(FValue)) then
    Exit;
 
  Inc(FIndex);
  Result := FIndex < Length(FValue);
end;
 
end.