在Delphi中搜索String数组

awm*_*oss 13 delphi

Delphi标准库中是否有一个函数来搜索特定值的字符串数组?

例如

someArray:=TArray<string>.Create('One','Two','Three');
if ArrayContains(someArray, 'Two') then
    ShowMessage('It contains Two');
Run Code Online (Sandbox Code Playgroud)

OnT*_*Fly 28

绝对没有必要重新发明轮子.StrUtils.MatchStr完成了这项工作.

procedure TForm1.FormCreate(Sender: TObject);
var
  someArray: TArray<string>;
begin
  someArray:=TArray<string>.Create('One','Two','Three');
  if MatchStr('Two', someArray) then
    ShowMessage('It contains Two');
end;
Run Code Online (Sandbox Code Playgroud)

请注意参数顺序约定.

另一个注意事项:MatchStr是在Delphi 7和Delphi 2007之间分配给该函数的规范化名称.历史名称是AnsiMatchStr(约定与RTL的其余部分相同:区分大小写的Str/Text后缀,MBCS/Locale的Ansi前缀) )

  • +1.太好了!我没有抓到那个(可能是因为这个名字与实际名称不符).你知道它出现的Delphi版本吗? (2认同)

Ken*_*ite 5

我写了一个模仿旧Clipper AScan功能(在中测试XE)的模型。@RRUZ的答案更正确(存在一个答案),但是我的不需要先对数组进行排序,并且在小型数组上足够快。(它也可以在Delphi的泛型版本中使用。)我还为各种类型的数组重载了它-这是stringand 的实现integer

// Returns the 0-based index of Value if it's found in the array,
// -1 if not. (Similar to TStrings.IndexOf)
function AScan(const Ar: array of string; const Value: string): Integer; overload;
var
  i: Integer;
begin
  Result := -1;
  for i := Low(Ar) to High(Ar) do
    if SameText(Ar[i], Value) then
    begin
      Result := i;
      Break
    end;
end;

function AScan(const Ar: array of Integer; const Value: Integer): Integer; overload;
var
  i: Integer;
begin
  Result := -1;
  for i := Low(Ar) to High(Ar) do
    if (Ar[i] = Value) then
    begin
      Result := i;
      Break
    end;
end;

procedure TForm2.FormShow(Sender: TObject);
var
  someStrArray: TArray<string>;
  someIntArray: TArray<Integer>;
  Idx: Integer;
begin
  someStrArray := TArray<string>.Create('One', 'Two', 'Three');
  Idx := AScan(someStrArray, 'Two');
  if Idx > -1 then
    ShowMessage(Format('It contains Two at index %d', [Idx]))
  else
    ShowMessage('Not found');
  someIntArray := TArray<Integer>.Create(8, 16, 32);
  Idx := AScan(someIntArray, 32);
  if Idx > -1 then
    ShowMessage(Format('It contains 32 at %d', [Idx]))
  else
    ShowMessage('16 not found');
end;
Run Code Online (Sandbox Code Playgroud)

对于支持泛型的Delphi版本,这是一个不需要对数组进行排序的版本,并且还允许您在需要时提供比较功能:

接口:

type
  TGenericsUtils = class
  public
    class function AScan<T>(const Arr: array of T; const Value: T; const Comparer: IEqualityComparer<T>):  Integer; overload;
    class function AScan<T>(const Arr: array of T; const Value: T): Integer; overload;
  end;
Run Code Online (Sandbox Code Playgroud)

实作

class function TGenericsUtils.AScan<T>(const Arr: array of T; const Value: T): Integer;
begin
  Result := AScan<T>(Arr, Value, TEqualityComparer<T>.Default);
end;

class function TGenericsUtils.AScan<T>(const Arr: array of T; const Value: T;
  const Comparer: IEqualityComparer<T>): Integer;
var
  i: Integer;
begin
  for i := Low(Arr) to High(Arr) do
    if Comparer.Equals(Arr[i], Value) then
      Exit(i);
  Exit(-1);
end;
Run Code Online (Sandbox Code Playgroud)

测试代码:

var
  AIntTest: TIntegerDynArray;
  AStrTest: TStringDynArray;

begin
  AIntTest := TIntegerDynArray.Create(12, 15, 6, 1, 4, 9, 5);
  AStrTest := TStringDynArray.Create('One', 'Six', 'Three', 'Four', 'Twelve');
  WriteLn('AIntTest contains 9 at index ', TGenericsUtils.AScan<Integer>(AIntTest, 9));
  WriteLn('AStrTest contains ''Four'' at index ', TGenericsUtils.AScan<String>(AStrTest, 'Four'));
  ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)

  • “ ..不,没有。”,[TArray.BinarySearch](http://docwiki.embarcadero.com/Libraries/en/System.Generics.Collections.TArray.BinarySearch)怎么样? (2认同)

RRU*_*RUZ 5

您可以使用该TArray.BinarySearch功能,它是Generics.Collections单元的一部分.

检查这个样本

{$APPTYPE CONSOLE}

{$R *.res}

uses    
  Generics.Defaults,
  Generics.Collections,
  System.SysUtils;

Var
  someArray: TArray<string>;
  FoundIndex : Integer;

begin
  try
    someArray:=TArray<string>.Create('a','b','c');
    if TArray.BinarySearch<String>(someArray, 'b', FoundIndex, TStringComparer.Ordinal) then
     Writeln(Format('Found in index %d',[FoundIndex]))
    else
     Writeln('Not Found');
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
Run Code Online (Sandbox Code Playgroud)

注意:BinarySearch要求对数组进行排序.

  • 对于一次性使用,你是对的,@ Krom.如果需要多次搜索数组,那么对数组进行排序是值得的.您为搜索排序所付出的代价会在搜索时节省.比较重复的O(N)搜索与一次O(N log N)排序,然后重复O(log N)搜索.如果执行的操作超过*log N*,则应首先对列表进行排序. (2认同)