Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Generische string.Split Funktion (https://www.delphipraxis.net/198022-generische-string-split-funktion.html)

DieDolly 27. Sep 2018 12:04

Generische string.Split Funktion
 
Ich habe eine FUnktion die eine einzige Zeile hat
Delphi-Quellcode:
Result := AString.Split([ADelimiter]);
Split liefert aber leider nur Strings zurück.

Wie bekomme ich diese Funktion generisch? Das hier klappt leider an der markierten Stelle nicht
Delphi-Quellcode:
function Explode<T>(const ADelimiter, AString: string): TArray<T>;
var
 LArr: TArray<string>;
 Li: Integer;
begin
 SetLength(Result, 0);
 LArr := AString.Split([ADelimiter]); // erst mal den String splitten und in ein string array speichern

 for Li := 0 to Length(LArr) - 1 do
  begin
   if (TypeInfo(T) = TypeInfo(string)) then
    TArrayHelper.Add<T>(Result, LArr[Li]); ///////// und hier jetzt Result als string array füllen

   // hier unten würde ich dasselbe gerne mit Integer machen
  end;
end;
Add sieht so aus
Delphi-Quellcode:
procedure TArrayHelper.Add<T>;
begin
 SetLength(Values, Length(Values) + 1);
 Values[High(Values)] := Value;
end;
Ich würde gerne eine einzige Explode-Funktion haben die einen String annimt und Strings oder Integer als Array zurückgibt.

TiGü 27. Sep 2018 12:34

AW: Generische string.Split Funktion
 
Delphi-Quellcode:
type
  TArrayHelper = record
  public
    class function Explode<T>(const ADelimiter, AString: string): TArray<T>; static;
  end;

class function TArrayHelper.Explode<T>(const ADelimiter, AString: string): TArray<T>;
var
  LArr: TArray<string>;
  LIntArr: TArray<Integer>;
  Li: Integer;
  I: Integer;
begin
  SetLength(Result, 0);
  LArr := AString.Split([ADelimiter]);

  for Li := 0 to Length(LArr) - 1 do
  begin
    if (TypeInfo(T) = TypeInfo(string)) then
    begin
      Result := TArray<T>(LArr);
    end
    else if (TypeInfo(T) = TypeInfo(Integer)) then
    begin
      SetLength(LIntArr, Length(LArr));
      for I := Low(LIntArr) to High(LIntArr) do
      begin
        LIntArr[I] := LArr[I].ToInteger;
      end;
      Result := TArray<T>(LIntArr);
    end;
  end;
end;

procedure Test;
var
  MyString: string;
  MyStringArray: TArray<string>;
  MyIntegerArray: TArray<Integer>;
begin
  MyString := '1,2,3';
  MyStringArray := TArrayHelper.Explode<string>(',', MyString);
  MyIntegerArray := TArrayHelper.Explode<Integer>(',', MyString);
end;

Uwe Raabe 27. Sep 2018 12:36

AW: Generische string.Split Funktion
 
Wenn die internen Umwandlungsmechanismen immer funktionieren, könnte das auch so gehen:
Delphi-Quellcode:
  for Li := 0 to Length(LArr) - 1 do begin
    TArrayHelper.Add<T>(Result, TValue.From(Larr[Li]).AsType<T>);
  end;
Eventuell würde ich hier aber eine TList<T> vorziehen:
Delphi-Quellcode:
  list := TList<T>.Create;
  try
    for Li := 0 to Length(LArr) - 1 do begin
      list.Add(TValue.From(Larr[Li]).AsType<T>);
    end;
    Result := list.ToArray;
  finally
    list.Free;
  end;

Stevie 27. Sep 2018 12:45

AW: Generische string.Split Funktion
 
Das funktioniert auf keinen Fall, Uwe. TValue konvertiert string nicht in andere Datentypen sondern nur in Typen, die zuweisungskompatibel sind und das sind String und Integer nicht.

In Spring hab ich diese Funktionalität, um einen durch Komma getrennten string in ein Array jeglichen Typs zu konvertieren, das benutzt aber interne TValue Konvertierungsmechanismen, die auch Teil von Spring sind.

Beispiel:
Delphi-Quellcode:
uses
  Spring;

var
  s: string = '1,2,3,4';
  nums: TArray<Integer>;
begin
  nums := TValue.From(s).ToType<TArray<Integer>>;
Dynamisches Array eines Typs in Dynamisches Array eines anderen Typs geht noch nicht, aber das bringt mich gerade auf eine Idee :mrgreen:

DieDolly 27. Sep 2018 12:53

AW: Generische string.Split Funktion
 
Danke für die Hilfe. Da war ich doch nicht so weit weg. Trotzdem hatte ich es falsch.

Anhand deiner Umwandlungen habe ich das auch mal mit einer Implode-Funktion versucht. Aber das geht leider in die Hose, da die Umwandlungen hier wohl anders sein sollen.

Meine originale Implode-Funktion
Delphi-Quellcode:
 // for i := 0 to Length(Values) - 1 do
 // begin
 // Res := Res + Values[i];
 //
 // if (i + 1 < Length(Values)) then
 // Res := Res + ADelimiter;
 // end;
oder eben

Delphi-Quellcode:
:= string.Join(',', StringArray);
Aber Join gibt es auch nicht für Integer-Arrays.

Mein Ziel: ein Integer-Array als String zurückzuliefern.

Ohne Generics würde ich das sonst so machen
Delphi-Quellcode:
function Implode(const ADelimiter: string; const Values: TArray<string>): string;
var
 i: Integer;
begin
 // Result := string.Join(ADelimiter, Values);
 // oder

 Result := '';

 for i := 0 to Length(Values) - 1 do
  begin
   Result := Result + Values[i];

   if (i + 1 < Length(Values)) then
    Result := Result + ADelimiter;
  end;
end;

function Implode(const ADelimiter: string; const Values: TArray<Integer>): string;
var
 i: Integer;
 StrArray: TArray<string>;
begin
 Result := '';

 for i := 0 to Length(Values) - 1 do
  begin
   SetLength(StrArray, Length(StrArray) + 1);
   StrArray[i] := IntToStr(Values[i]);
  end;

 Result := Implode(ADelimiter, StrArray);
end;

Uwe Raabe 27. Sep 2018 13:07

AW: Generische string.Split Funktion
 
Zitat:

Zitat von Stevie (Beitrag 1414315)
TValue konvertiert string nicht in andere Datentypen sondern nur in Typen, die zuweisungskompatibel sind und das sind String und Integer nicht.

Stimmt! Ich hatte mich von der Konvertierung bei ToString verleiten lassen.

Stevie 27. Sep 2018 13:21

AW: Generische string.Split Funktion
 
Zitat:

Zitat von DieDolly (Beitrag 1414316)
Mein Ziel: ein Integer-Array als String zurückzuliefern.

Wenn du eine fest bestimmte Menge an Typen hast, die du behandeln möchtest, würd ich dir von Generics abraten und die entsprechenden Typen per Überladungen implementieren.

DieDolly 27. Sep 2018 13:36

AW: Generische string.Split Funktion
 
Zitat:

Zitat von Stevie (Beitrag 1414319)
Zitat:

Zitat von DieDolly (Beitrag 1414316)
Mein Ziel: ein Integer-Array als String zurückzuliefern.

Wenn du eine fest bestimmte Menge an Typen hast, die du behandeln möchtest, würd ich dir von Generics abraten und die entsprechenden Typen per Überladungen implementieren.

Habe ich bei der Implodefunktion so gemacht. Bei der Explode-Funktion nutze ich aber dann doch Generics, weil sich nur das Resultat der Funktion ändert aber nicht die Parameter.
Unschöne Out-Parameter wären das Resultat.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:58 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz