Zoek in een String-array in Delphi

Is er een functie in de Delphi-standaardbibliotheek om tekenreeksen te zoeken voor een bepaalde waarde?

bijv.

someArray:=TArray.Create('One','Two','Three');
if ArrayContains(someArray, 'Two') then
    ShowMessage('It contains Two');
13
Als u Sorteren wilt, kunt u eerst BinarySearch gebruiken, maar ik ken er geen voor een niet-gesorteerde TArray , hopelijk iemand doet.
toegevoegd de auteur Seth Carnegie, de bron
Ik gebruik meestal een for-lus.
toegevoegd de auteur Marcus Adams, de bron

3 antwoord

Het wiel is absoluut niet opnieuw uit te vinden. StrUtils.MatchStr doet het werk.

procedure TForm1.FormCreate(Sender: TObject);
var
  someArray: TArray;
begin
  someArray:=TArray.Create('One','Two','Three');
  if MatchStr('Two', someArray) then
    ShowMessage('It contains Two');
end;

Let op de volgorde van de parametervolgorde.

Een andere opmerking: MatchStr is een geanonimiseerde naam die is toegewezen aan deze functie tussen Delphi 7 en Delphi 2007. Historische naam is AnsiMatchStr (conventie is hetzelfde als in de rest van RTL : Str/Text suffix voor hoofdlettergevoeligheid, Ansi-prefix voor MBCS/Locale)

27
toegevoegd
Het heeft weinig zin om geparametriseerde typeaangifte te gebruiken tijdens het werken met arrays. Arrays zijn geen klassen en kunnen niet worden uitgebreid om bijvoorbeeld te ondersteunen. Java-stijl Array.indexOf
toegevoegd de auteur OnTheFly, de bron
@awmross, dat was meer een teken voor mezelf. Kijk naar System.TAry en Generics.Collections.TApy . Het zijn zeer verschillende typen en ik denk dat het vermengen ervan erg misleidend is (ik weet wat je gebruikt Generics.Collections.Tream .Create alleen om de open array-constructor te gebruiken)
toegevoegd de auteur OnTheFly, de bron
1. Leuk! Ik had die niet gepakt (waarschijnlijk omdat de naam niet overeenkomt met wat hij eigenlijk doet). Weet jij waar de Delphi-versie in verscheen?
toegevoegd de auteur Ken White, de bron
Eh ... ik weet niet precies wat je laatste opmerking is waarnaar wordt verwezen. Parameterafhankelijke typedeclaraties zijn nodig bij het behandelen van pre-generieke versies van Delphi, en deze was niet getagd met een specifieke Delphi-versie (hoewel het een generieke array gebruikt). Bekritiseer je het feit dat ik je een upvote heb gegeven? Als dat zo is, kan ik het terugnemen. :)
toegevoegd de auteur Ken White, de bron
Ik begrijp ook de opmerking over geparametriseerde typeaangiften niet. Wil je uitbreiden?
toegevoegd de auteur awmross, de bron

je kunt de TArray.BinarySearch -functie, die deel uitmaakt van de Generics.Collections-eenheid.

controleer dit voorbeeld

{$APPTYPE CONSOLE}

{$R *.res}

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

Var
  someArray: TArray;
  FoundIndex : Integer;

begin
  try
    someArray:=TArray.Create('a','b','c');
    if TArray.BinarySearch(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.

Note: BinarySearch requires that the array be sorted.

5
toegevoegd
Voor een eenmalig gebruik hebt u gelijk, @Krom. Als u de array meerdere keren moet doorzoeken, kan het de tijd waard worden om de array te sorteren. De prijs die u betaalt om de array te sorteren, betaalt zich terug in de tijd die u spaart bij het zoeken. Vergelijk herhaalde O (N) zoekopdrachten met een eenmalige O (N log N) sortering gevolgd door herhaalde O (log N) zoekopdrachten. Als u meer dan log N -zoekt, moet u eerst de lijst sorteren.
toegevoegd de auteur Rob Kennedy, de bron
Ik heb het gevoel dat het gebruik van de voor lus op de ongesorteerde array sneller zal zijn dan het sorteren zelf ..
toegevoegd de auteur Kromster, de bron
@Rob: Absoluut mee eens.
toegevoegd de auteur Kromster, de bron
Helaas, ja.
toegevoegd de auteur RRUZ, de bron
zal dit werken? "Opmerking: BinarySearch vereist dat de array wordt gesorteerd.". Moet u de array eerst sorteren?
toegevoegd de auteur awmross, de bron

Ik heb er een geschreven die ik heb gemodelleerd naar de oude functie Clipper AScan (getest in XE ). @ RRUZ's antwoord is correcter (er is er één), maar de mijne vereist niet dat de array eerst wordt gesorteerd en is snel genoeg op kleine arrays. (Het werkt ook in pre-generieke versies van Delphi.) Ik overbelast het ook voor verschillende soorten array - hier zijn de implementaties voor string en 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;
  someIntArray: TArray;
  Idx: Integer;
begin
  someStrArray := TArray.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.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;

Voor versies van Delphi die generieke geneesmiddelen ondersteunen, is hier een versie waarvoor de array niet hoeft te worden gesorteerd, en waarmee u desgewenst ook de vergelijkingsfunctie kunt opgeven:

Interface:

type
  TGenericsUtils = class
  public
    class function AScan(const Arr: array of T; const Value: T; const Comparer: IEqualityComparer):  Integer; overload;
    class function AScan(const Arr: array of T; const Value: T): Integer; overload;
  end;

Implementatie

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

class function TGenericsUtils.AScan(const Arr: array of T; const Value: T;
  const Comparer: IEqualityComparer): 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;

Testcode:

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(AIntTest, 9));
  WriteLn('AStrTest contains ''Four'' at index ', TGenericsUtils.AScan(AStrTest, 'Four'));
  ReadLn;
end.
4
toegevoegd
"..Nee, dat is er niet.", Hoe zit het met TArray.BinarySearch ?
toegevoegd de auteur RRUZ, de bron
Ach, heb die gemist (zag de generieken niet toen ik dat schreef; ik ving ze op toen ik de code schreef om te reageren, maar de fout niet oploste). Bedankt, Rodrigo. :) Gecorrigeerd, en +1 op je antwoord omdat je meer correct bent.
toegevoegd de auteur Ken White, de bron