Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Slicing for Delphi™ (https://www.delphipraxis.net/131414-slicing-delphi%99.html)

Meflin 24. Mär 2009 17:05


Slicing for Delphi™
 
Liste der Anhänge anzeigen (Anzahl: 2)
Moin moin!

Der eine oder andere von euch kennt sicher aus anderen Programmiersprachen das Slicing-Konzept. Für die, die es nicht kennen, hier eine kurze Einführung:

Dass man auf ein Listenelement mittels Liste[Index] zugreifen kann, ist sicher nichts neues. Das dumme daran: Man bekommt immer nur ein Element zurück. Und hier kommt das Slicing ins Spiel, welches derartige Zugriffe quasi exponentiell nützlicher macht.

Die Grundlegende Syntax ist Liste[StartIndex:StopIndex]. Und eigentlich ist das schon ziemlich selbsterklärend, hier ein paar Beipsiele, was man damit so machen kann:
Code:
Liste[0:4]   0tes - 5tes Element
Liste[3:4]   4tes - 5tes Element
Liste[:5]    0tes - 6tes Element
Liste[3:]    4tes - letztes Element
Liste[1:-1]  zweites - vorletztes Element

u.v.m.
Nun, wems bis jetzt noch nicht gedämmert ist: Soetwas gibt es in Delphi leider nicht :(

Ich bin grade dabei mir zu überlgen, inwieweit man das in Delphi integrieren könnte. Herausgekommen ist dabei bis jetzt eine Beispielimplementation TSlicedStringList:
Delphi-Quellcode:
unit SlicedStringList;

interface

uses
  Classes;

type
  TSlicedStringList = class(TStringList)
  private
    function GetStrings(Slice: string): TStrings;
    //procedure SetStrings(Slice: string; const Value: TStrings);
  public
    property Strings[Index: Integer]: string read Get write Put; default;
    property Strings[Slice: string]: TStrings read GetStrings; default;
  end;

implementation

uses
  SysUtils, Dialogs;

{ TExtStringList }
type
  TIntArray = array of Integer;

function GetIntArrayFromSlice(const Slice: string; const Max: Integer): TIntArray;
var
  strStartPos, strStopPos: string;
  StartPos, StopPos, i: Integer;
begin
  strStartPos := Copy(Slice, 1, Pos(':', Slice) - 1);
  strStopPos := Copy(Slice, Pos(':', Slice) + 1, Length(Slice));

  case Length(strStartPos) of
    0: StartPos := 0;
    else StartPos := StrToInt(strStartPos);
  end;

  case Length(strStopPos) of
    0: StopPos := Max;
    else StopPos := StrToInt(strStopPos);
  end;

  if StartPos < 0 then StartPos := Max + StartPos;
  if StopPos < 0 then StopPos := Max + StopPos;

  SetLength(Result, StopPos - StartPos + 1);
  for i := StartPos to StopPos do begin
    Result[i - StartPos] := i;
  end;
end;

function TSlicedStringList.GetStrings(Slice: string): TStrings;
var
  i: Integer;
begin
  Result := TStringList.Create;
  case Pos(':', Slice) of
    0: Result.Add(Strings[StrToInt(Slice)]);
    else begin
      for i in GetIntArrayFromSlice(Slice, Count - 1) do
        Result.Add(Strings[i]);
    end;
  end;
end;

//procedure TSlicedStringList.SetStrings(Slice: string; const Value: TStrings);
//begin
//
//end;

end.
Das neue an ihr: sowas geht
Delphi-Quellcode:
lst := StringList['1:4'];
Im Anhang findet ihr eine kleine Demo-Anwendung dazu, nix großes, soll nur das Prinzip verdeutlichen und enthält KEINE Fehlerabfragen, derartige 'Bugreports' sind also überflüssig ;)




Die spannende Frage ist nun:
Was haltet ihr davon? Nützlich? Fürn Popo? Unbedingt weiterentwicklen?

Und wenn weiterentwickeln, was wären die Konventionen, die ihr bevorzugegen würdet?
Soll [-1] Das letzte oder das vorletzte Element liefern? (Beides ergibt Sinn).
Soll der EndIndex im Ergebnis enthalten sein oder nicht (beide Versionen gibt es in anderen Sprachen).

Fällt euch eine bessere Möglichkeit ein, als das ganze per string zu übergeben (was nicht sehr nützlich ist, aber es ist der einizge Weg, der mir spontan eingefallen ist)?


Nuja, her mit euren Ideen und Anregungen :)

Namenloser 24. Mär 2009 17:13

Re: Slicing for Delphi™
 
Zitat:

Zitat von Meflin
Fällt euch eine bessere Möglichkeit ein, als das ganze per string zu übergeben (was nicht sehr nützlich ist, aber es ist der einizge Weg, der mir spontan eingefallen ist)?

Ich würde es so machen, wie bei TCanvas.Pixels:
Delphi-Quellcode:
TSlicedStringList = class
private
  function GetSlice(From, To: integer): TStrings;
  ...

public
  property Slices[From,To: integer]: TStrings read GetSlice;
  ...

end;

...
Delphi-Quellcode:
lst := SlicedStringList.Slices[1,4];
lst.free;

Meflin 24. Mär 2009 17:25

Re: Slicing for Delphi™
 
Zitat:

Zitat von NamenLozer
Ich würde es so machen, wie bei TCanvas.Pixels

Habe ich auch drüber nachgedacht, der Nachteil daran ist, dass das spaßige von-rechts-Zählen quasi komplett wegfällt, weil man immer zwei Parameter angeben muss.
[-1] Wäre das letzte Element, [0, -1] würde was anderes bedeuten, man müsste dafür also [-1, -1] übergeben.

Auch irgendwie blöd :|

mr_emre_d 24. Mär 2009 17:35

Re: Slicing for Delphi™
 
Zitat:

Zitat von Meflin
Zitat:

Zitat von NamenLozer
Ich würde es so machen, wie bei TCanvas.Pixels

Habe ich auch drüber nachgedacht, der Nachteil daran ist, dass das spaßige von-rechts-Zählen quasi komplett wegfällt, weil man immer zwei Parameter angeben muss.
[-1] Wäre das letzte Element, [0, -1] würde was anderes bedeuten, man müsste dafür also [-1, -1] übergeben.

Auch irgendwie blöd :|

Ich habe heir mal eine kleine rekursive Function gepostet, mit der man einen Wert in einem Wertebereich, die man angibt, zurückbekommt !

EDIT:
http://www.delphipraxis.net/internal...929&highlight=
Siehe mein Beitrag

MfG

shmia 24. Mär 2009 17:46

Re: Slicing for Delphi™
 
Interessant!
Ich würde das mit dem Dekorator Design-Pattern lösen.
Dazu leitet man von TStrings ab und muss dann natürlich alle virtuellen (und abstrakten) Methoden überschreiben.
Dabei leitet man die Methoden nur auf das TStrings-Objekt weiter, dass im Konstruktor übergeben wurde.
Delphi-Quellcode:
TSlicedStrings = class(TStrings)
private
   FStrings : TStrings;
   function GetSlice(const Range: string): TStrings;
   //procedure SetStrings(Slice: string; const Value: TStrings);
public
   constructor Create(AStrings:TStrings);
   function Add(const S: string): Integer; override;

   property Slice[const Range: string]: TStrings read GetStrings;
   property Slice[fromIdx,toIdx:Integer]:TStrings; // 2. Variante
end;
constructor TSlicedStrings.Create(AStrings:TStrings);
begin
  inherited Create;
  FStrings := AStrings;
end;
function TSlicedStrings.Add(const S: string): Integer; override;
begin
  Result := FStrings.Add(S); // einfach auf internes Objekt umleiten
end;


function TSlicedStrings.GetSlice(const Range: string): TStrings;
var
  i,j : Integer;
begin
  Result := TStringList.Create;
  case Pos(':', Range) of
    0:
    begin
      j := StrToInt(Range);
       Result.AddObject(Strings[j], Objects[j]);
    end
    else begin
      for i in GetIntArrayFromSlice(Range, Count - 1) do
        Result.AddObject(Strings[i], Objects[i]);
    end;
  end;
end;

Dax 24. Mär 2009 17:50

Re: Slicing for Delphi™
 
Zitat:

Zitat von Meflin
[-1] Wäre das letzte Element, [0, -1] würde was anderes bedeuten, man müsste dafür also [-1, -1] übergeben.

Auch irgendwie blöd :|

Du könntest zwei Properties einbauen, einmal mit einem Parameter, einmal mit zwei. Ob man beide defaulten kann, weiß ich gerade nicht - aber schöner als Strings zu verwenden wäre es allemal.

alzaimar 24. Mär 2009 18:50

Re: Slicing for Delphi™
 
Lustig. Der Nachteil des String-Parametersi ist die etwas sehr umständliche Verwurstung von Variablen. I.A. benötige ich nicht das 2. bis 5. Element, sondern das i.te bis j.te (bzw. N Elemente ab Position I). Ich müsste mir also den Deskriptorstring mittels IntToStr oder Format zusammenbasteln. Das ist irgendwie blöd.

Delphi-Quellcode:
MySlicedStringList := StringList[Format('%d:%d',[I,N])];
Übersichlich geht anders.

Meflin 24. Mär 2009 19:04

Re: Slicing for Delphi™
 
Zitat:

Zitat von alzaimar
Der Nachteil des String-Parametersi ist die etwas sehr umständliche Verwurstung von Variablen ... Übersichlich geht anders.

Da hast du völlig Recht und das ist mir auch bewusst. Nur wenn man beim "originalen" Slicing bleibt, dann ist ja [:-1] etwas anderes als [-1] (nämlich einmal die komplette Liste und einmal das letzte Element). Die Dynamik geht irgendwie verloren, wenn man mehrere properties implementiert :gruebel: Auch gibt es ja noch erweiterte Slicing-Techniken, [1::2] wäre jedes zweite Element, oder [1::3] jedes dritte beginnend mit dem zweiten. Ich weiß nicht ob ich sowas überhaupt implementieren will. Aber da endet dann der Umgang mit blosen Integern.

Zitat:

Zitat von Dax
Du könntest zwei Properties einbauen, einmal mit einem Parameter, einmal mit zwei. Ob man beide defaulten kann, weiß ich gerade nicht

Das sollte möglich sein.

Zitat:

Zitat von shmia
Ich würde das mit dem Dekorator Design-Pattern lösen.
Dazu leitet man von TStrings ab und muss dann natürlich alle virtuellen (und abstrakten) Methoden überschreiben.
Dabei leitet man die Methoden nur auf das TStrings-Objekt weiter, dass im Konstruktor übergeben wurde.

Danke, das ist ein interessanter Ansatz :thumb:

Zitat:

Zitat von mr_emre_d
Ich habe heir mal eine kleine rekursive Function gepostet, mit der man einen Wert in einem Wertebereich, die man angibt, zurückbekommt !

Hm. Welches Problem meintest du soll die Lösen :stupid: ?

mr_emre_d 24. Mär 2009 20:17

Re: Slicing for Delphi™
 
xD
Um etwas klarzustellen -> meinst du mit [0:-1] ~ [0:Anzahl der Rechten Elemente - 1] ?

Falls nein, dann war mal mein Beitrag wieder voll daneben :roll:

MfG

himitsu 24. Mär 2009 21:46

Re: Slicing for Delphi™
 
bei Arrays kann man auch Copy nutzen ... ok, ohne das "von rechts"
Delphi-Quellcode:
var a: Array of Double;

a := Copy(a, 5, 9);
ansonsten gibt's 2 Möglichkeiten für die Parameter:
Delphi-Quellcode:
public
  property Slices[From: Integer; To: Integer = MinInt]: TStrings read GetSlice;

// if To = MinInt then {to=from}
// else {from,to}
Delphi-Quellcode:
public
  property Slices[From, To: Integer]: TStrings read GetSlice2; Default;
  property Slices[To:      Integer]: TStrings read GetSlice1; Default;
  ...


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:51 Uhr.
Seite 1 von 3  1 23      

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