Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Werte aus dynamischen array löschen (https://www.delphipraxis.net/175412-werte-aus-dynamischen-array-loeschen.html)

jupiter4065139 19. Jun 2013 16:11

Werte aus dynamischen array löschen
 
Hallo,

ich hab mir meine Werte aus einem stream in ein array eingelesen

Delphi-Quellcode:
while Stream.Position < Stream.Size do begin
            Stream.ReadBuffer(Digit, SizeOf(Digit));
            Inc(byte);
 time:= time+ 1/250;
setlength(arr,stream.size);
arr[fs.position].zeit:= time;
arr[fs.position].wert:=Digit;
ich wollt mir jetzt ne schleife bauen, worin die Zeitwerte in einem bestimmten Bereich gelöscht werden. Die jeweiligen digit werte sollen aber auch mit gelöscht werden. D.h. die gesamte Zeile soll gelöscht werden.
Delphi-Quellcode:
               Begin
               If (median[FS.Position].Zeit > 0.1 and median[FS.Position].Zeit < 0.2) then
             
               begin
                  // hier dachte ich steht der code zum löschen
              end;
              end;
kann da jemand ein tipp geben?

baumina 19. Jun 2013 16:57

AW: Werte aus dynamischen array löschen
 
http://www.delphi-treff.de/tipps/obj...ecke-entsteht/

Uwe Raabe 19. Jun 2013 17:03

AW: Werte aus dynamischen array löschen
 
Tip: Wenn du über eine for-Schleife Elemente aus einem Array löscht, dann lass die Schleife rückwärts laufen.

BUG 19. Jun 2013 22:21

AW: Werte aus dynamischen array löschen
 
Ich würde eher an sowas denken:
Delphi-Quellcode:
var aArray: array of Something;
var writePos, readPos, retained: integer;
//...
writePos := 0;
retained := 0;
for readPos := 0 to length(aArray)-1 do
begin
  if condition(aArray[readPos]) then
  begin
    if (readPos <> writePos) then aArray[writePos] := aArray[readPos];
    inc(writePos);
    inc(retained);
  end;
end;
setLength(aArray, retained);
Also insgesamt: Die Elemente, die du behalten willst, am Anfang des Arrays anordnen.
Dabei werden möglicherweise unerwünschte überschrieben und erwünschte dupliziert. Dann wird der Rest einfach abgeschnitten (setLength).

Das Ganze könnte man eventuell als generische filter-Operation für Arrays verpacken, aber ich bin nicht so fit mit Generics in Delphi.

Bummi 19. Jun 2013 22:28

AW: Werte aus dynamischen array löschen
 
:gruebel:

BUG 19. Jun 2013 22:46

AW: Werte aus dynamischen array löschen
 
Zitat:

Zitat von Bummi (Beitrag 1219124)
:gruebel:

Möchte jupiter nicht mehrere Zeilen löschen, bei denen eine bestimmte Bedingung zutrifft :gruebel:

Bummi 19. Jun 2013 22:54

AW: Werte aus dynamischen array löschen
 
Ich habe es nicht getestet, aber wenn z.B. Element 5 gelöscht werden soll, würde IMHO Element
0 mit dem Wert von Element 5 überschrieben und das letzte Element z.B. 10 nach dem Durchlauf gelöscht ....
writePos und retained beinhalten die selben Werte ...

Wenn Condition invers gemeint ist fehlt IMHO ein else Zweig

Zitat:

var aArray: array of Something;
var writePos, readPos, retained: integer;
//...
writePos := 0;
retained := 0;
for readPos := 0 to length(aArray)-1 do
begin
if condition(aArray[readPos]) then
begin
if (readPos <> writePos) then aArray[writePos] := aArray[readPos];
inc(writePos);
inc(retained);
end;
end;
setLength(aArray, retained);

BUG 19. Jun 2013 23:22

AW: Werte aus dynamischen array löschen
 
Zitat:

Zitat von Bummi (Beitrag 1219126)
Wenn Condition invers gemeint ist fehlt IMHO ein else Zweig

OK, stimmt ... das ist verwirrend:
Delphi-Quellcode:
condition(element)
soll
Delphi-Quellcode:
true
sein, wenn
Delphi-Quellcode:
element
im Array behalten werden soll.
Mir ist aber nicht klar, was für ein else-Zweig fehlen sollte?


Angenommen ich will aus dem Array [0 1 2 3 4] alle geraden Zahlen herausfiltern.


Vor 1. Schleifendurchlauf:
Code:
         [0 1 2 3 4]
readPos   0
writePos  0
retained 0
Vor 2. Schleifendurchlauf:
Code:
         [0 1 2 3 4]
readPos     1
writePos    1
retained   1
Vor 3. Schleifendurchlauf:
Code:
         [0 1 2 3 4]
readPos       2
writePos    1
retained    1
Vor 4. Schleifendurchlauf:
Code:
         [0 2 2 3 4]
readPos         3
writePos      2
retained     2
Vor 5. Schleifendurchlauf:
Code:
         [0 2 2 3 4]
readPos           4
writePos      2
retained     2
Ende der Schleife:
Code:
         [0 2 4|3 4]
readPos?       |
writePos       |3
retained       3

setLength(aArray, retained) => [0 2 4]
Dabei fällt mir auf, dass
Delphi-Quellcode:
writePos
und
Delphi-Quellcode:
retained
immer gleich sind; man könnte sich also eine der Variablen sparen :mrgreen:

Bummi 20. Jun 2013 06:18

AW: Werte aus dynamischen array löschen
 
versuch es mal mit einem Array von 0 bis 9 und der Bedingung
Delphi-Quellcode:
if ((aArray[readPos]))=5 then
Mit einem kleinen Umbau sollte es funktionieren

Delphi-Quellcode:
var
  aArray: array of Integer;
  i, writePos, readPos, retained: Integer;

  Function Condition(i: Integer): Boolean;
  begin
    //Result := (i and 1)=0 ;
    Result := i in [0, 3, 7];
  end;

begin
  writePos := 0;
  retained := 0;

  setlength(aArray, 10);
  For i := 0 to 9 do
    aArray[i] := i;

  retained := Length(aArray);
  for readPos := 0 to Length(aArray) - 1 do
  begin
    if Condition(aArray[readPos]) then
    begin
      dec(retained);
      dec(writePos);
    end
    else
      aArray[writePos] := aArray[readPos];
    inc(writePos);
  end;
  setlength(aArray, retained);
end;

BUG 20. Jun 2013 07:36

AW: Werte aus dynamischen array löschen
 
Zitat:

Zitat von Bummi (Beitrag 1219130)
versuch es mal mit einem Array von 0 bis 9 und der Bedingung
Delphi-Quellcode:
if ((aArray[readPos]))=5 then

Heraus kommt (wie erwartet) das Array [5].

Delphi-Quellcode:
  var
  aArray: array of Integer;
  i, writePos, readPos, retained: Integer;

  Function retainElement(i: Integer): Boolean;
  begin
    //Result := (i and 1)=0 ;
    //Result := i in [0, 3, 7];
    Result := i = 5;
  end;

  procedure print(a: array of integer);
  var i: integer;
  begin
    for i := 0 to length(a)-1 do WriteLn(a[i]);
  end;


begin
  writePos := 0;
  retained := 0;

  setlength(aArray, 10);
  For i := 0 to 9 do
    aArray[i] := i;

  writePos := 0;
  retained := 0;
  for readPos := 0 to length(aArray)-1 do
  begin
    if retainElement(aArray[readPos]) then
    begin
      if (readPos <> writePos) then aArray[writePos] := aArray[readPos];
      inc(writePos);
      inc(retained);
    end;
  end;
  setLength(aArray, retained);

  print(aArray);
  readln;
end.

Unser Code unterscheidet sich nur:
  • in der Bedeutung von
    Delphi-Quellcode:
    condition(aArray)
    ,
  • der Zählrichtung von
    Delphi-Quellcode:
    retained
    ,
  • darin, dass du
    Delphi-Quellcode:
    writePos
    immer inkrementierst, aber im Falle des Löschens eines Elements vorher dekrementierst.

Bummi 20. Jun 2013 08:56

AW: Werte aus dynamischen array löschen
 
:wall::wall: Danke ... mein Verständnis von condition war der Anlass für den Hänger ...

jupiter4065139 20. Jun 2013 09:38

AW: Werte aus dynamischen array löschen
 
ich hab das mal probiert nach
http://www.delphi-treff.de/tipps/obj...ecke-entsteht/


Delphi-Quellcode:
If (median[FS.Position].Zeit > 0.1 and median[FS.Position].Zeit < 0.2) then
             
begin

move(median[fs.position+1], median[fs.position], sizeOf(median[0])*(Length(median) - fs.position - 1));
                setlength(median, length(median)-1);

end;
Da werden aber in den Bereich nur "0" geschrieben. Das Problem liegt IMHO daran das fs.position als byte deklariert sind, oder? Die Daten aus der Datei werden als smallint ausgelesen, d.h. wenn ich mir fs.position anzeigen lasse wird immer um 2 byte erhöht.

Wenn ich jetzt fs.position als Index nehme geht das denk ich nich. Wie mach ich denn das dann am besten?

baumina 20. Jun 2013 10:04

AW: Werte aus dynamischen array löschen
 
Deswegen kam dieser Hinweis:

Zitat:

Zitat von Uwe Raabe (Beitrag 1219104)
Tip: Wenn du über eine for-Schleife Elemente aus einem Array löscht, dann lass die Schleife rückwärts laufen.

Mit Byte oder SmallInt hat das meiner Meinung nach nichts zu tun.

jupiter4065139 20. Jun 2013 10:44

AW: Werte aus dynamischen array löschen
 
Delphi-Quellcode:
If median[FS.Position].Zeit < 0.2) and (median[FS.Position].Zeit > 0.1 then


meinst du so? Da ändert sich aber nichts. kommen trotzdem nur "0".

Uwe Raabe 20. Jun 2013 10:54

AW: Werte aus dynamischen array löschen
 
Zitat:

Zitat von jupiter4065139 (Beitrag 1219169)
Delphi-Quellcode:
If median[FS.Position].Zeit < 0.2) and (median[FS.Position].Zeit > 0.1 then


meinst du so? Da ändert sich aber nichts. kommen trotzdem nur "0".

Das ist doch nur die Bedingung und nicht die Schleife. Warum lässt du denn das ganze Drumherum weg?

baumina 20. Jun 2013 10:58

AW: Werte aus dynamischen array löschen
 
Deine If-Abfrage befindet sich sicherlich innerhalb irgendeiner Schleife (while/repeat/for), diese solltest du Rückwärts laufen lassen.

jupiter4065139 20. Jun 2013 11:08

AW: Werte aus dynamischen array löschen
 
sorry, ich bin noch blutiger Anfänger (war etwas daneben)

Delphi-Quellcode:
while Stream.Position < Stream.Size do begin
            Stream.ReadBuffer(Digit, SizeOf(Digit));
            Inc(byte);
 time:= time+ 1/250;
setlength(arr,stream.size);
arr[stream.position].zeit:= time;
arr[stream.position].wert:=Digit;

If (arr[stream.Position].Zeit > 0.1 and arr[stream.Position].Zeit < 0.2) then

begin

move(arr[stream.position+1], arr[stream.position], sizeOf(arr[0])*(Length(arrn) - stream.position - 1));
                setlength(arr, length(arr)-1);

end;

end;
sowas dann ungefähr

Delphi-Quellcode:
while Stream.Position < Stream.Size do begin
            Stream.ReadBuffer(Digit, SizeOf(Digit));
            dec(byte);
wie mach ich denn dann das, ich müsste ja die stream.position an das ende setzen

baumina 20. Jun 2013 12:24

AW: Werte aus dynamischen array löschen
 
Vielleicht solltest du nicht darüber nachdenken überflüssige Einträge aus dem Array heraus zu löschen, sondern lieber unerwünschte Einträge in das Array erst gar nicht hinein zu schreiben. Ungefähr so:

Delphi-Quellcode:
setlength(arr,0);

while Stream.Position < Stream.Size do
begin
  Stream.ReadBuffer(Digit, SizeOf(Digit));
  Inc(byte);
  time:= time+ 1/250;
  If (time <= 0.1) or (time >= 0.2) then
  begin
    setlength(arr,Length(arr) + 1);
    arr[Length(arr)].zeit:= time;
    arr[Length(arr)].wert:= Digit;
  end;
end;
ungetestet

Uwe Raabe 20. Jun 2013 13:37

AW: Werte aus dynamischen array löschen
 
Da ist schon mal ein grundsätzlicher Fehler: du indizierst das Array nach der Stream.Position. Die ist aber immer Byte-orientiert und würde nur dann Sinn machen, wenn Digit auch als Byte deklariert ist. Sollte das aber der Fall sein, dann ist in jedem Fall des SetSize innerhalb der while-Schleife falsch und effizienter würde man das Array in einem Rutsch aus dem Stream füllen und danach weiter bearbeiten.

Also zeig doch bitte mal noch mehr von deinem Code.

Übrigens: Byte ist ein vordefinierter Datentyp. Delphi lässt zwar die Deklaration einer Variablen dieses Namens zu und behandelt das i.A. auch korrekt, es ist aber kein guter Stil solche Namen zu vergeben.

jupiter4065139 20. Jun 2013 14:32

AW: Werte aus dynamischen array löschen
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1219195)
Da ist schon mal ein grundsätzlicher Fehler: du indizierst das Array nach der Stream.Position. Die ist aber immer Byte-orientiert und würde nur dann Sinn machen, wenn Digit auch als Byte deklariert ist.

Genau das ist ja mein Problem. Wie müsste ich denn den stream einlesen, damit der mit einer integer Variablen indiziiert ist. Ich hab das bisher mit der .position gemacht, weil das erst mal funktionierte. Wenn ich dort jetzt aber eine schleife reinsetze kriege ich probleme.

Delphi-Quellcode:
type
    TDatensatz = record
        Zeit:Extended;
        U:Extended;      
        end;
    TDatenarray = array of TDatensatz ;

 
arr:TDatenarray;
 var j:byte;
 x, bis:integer;
 digit:smallint;
Stream,Stream2:TFilestream;
time, spannung:extended;
Listen:String;
begin
try
          j := 0;
          time:=0;
         
          while stream.Position < stream.Size do begin
            stream.ReadBuffer(Digit, SizeOf(Digit));
            inc(j);
              Spannung:= 10 * digit / 32768;
              time:=time+1/250;
                   setlength(arr, fs.size);
                      arr[stream.Position].Zeit:=time;
                      arr[stream.position].U:=Spannung;
     
            for x:= 0 to bis DO //bis wird über inputbox gelesen
               Begin
               if arr[stream.position].zeit > 0.1*x and arr[stream.position].zeit < 0.2*x then  //die Bedingung sieht eigentlich anders aus, aber so in der art
                  begin
                     // den Bereich wollte ich jetzt löschen
                        move(arr[stream.position+1], arr[stream.position], sizeof(arr[0])*(length(arr) -stream.position-1));
                        setlength(arr, length(arr)+1);        
                  end;
              end;
//ab hier in einen 2.stream speichern
             Listen := floattostr(arr[stream.position].zeit) + #9 + FloatToStr(arr[stream.position].U) + #9 + #13#10;  //AK
              Stream2.WriteBuffer(Listen[1], Listen(string));
             Listen := '';
              j   := 0;

            end;
            end;
finally
          stream.Free;
          stream2.Free;
        end;

Uwe Raabe 20. Jun 2013 14:49

AW: Werte aus dynamischen array löschen
 
Zitat:

Zitat von jupiter4065139 (Beitrag 1219213)
Delphi-Quellcode:
            for x:= 0 to bis DO //bis wird über inputbox gelesen
               Begin
               if arr[stream.position].zeit > 0.1*x and arr[stream.position].zeit < 0.2*x then  //die Bedingung sieht eigentlich anders aus, aber so in der art
                  begin
                     // den Bereich wollte ich jetzt löschen
                        move(arr[stream.position+1], arr[stream.position], sizeof(arr[0])*(length(arr) -stream.position-1));
                        setlength(arr, length(arr)+1);        
                  end;
              end;

Die echte Bedingung wäre hier aber schon wichtig, da dein Beispiel überhaupt keinen Sinn macht. Welche Werte sollen denn nun genau gelöscht werden. Danach kann man nämlich nur die Strategie für das Löschen festlegen.

jupiter4065139 20. Jun 2013 15:30

AW: Werte aus dynamischen array löschen
 
Das mit dem x ist wirklich verwirrend. Ich will einfach einen bestimmten Bereich aus der Zeitreihe entfernen.
D.h. vor den Spannungswerten aus dem Stream soll eine Zeitreihe gesetzt werden (alles innerhalb von stream.position < stream.size)

Delphi-Quellcode:
 time:=time+1/250;
und aus dieser reihe soll der Bereich zwischen
Delphi-Quellcode:
           
               if arr[stream.position].zeit > 0.1  and arr[stream.position].zeit < 0.2 then  
                 \\löschen
              end;
gelöscht und aufgerückt werden. Natürlich die zugehörigen Spannungswerten aus
Delphi-Quellcode:
arr[stream.position].U
auch.

jupiter4065139 20. Jun 2013 15:55

AW: Werte aus dynamischen array löschen
 
Am Besten wäre das ich mir die Daten aus dem Stream in ein dynamisches Array so übergebe, dass das nicht mit fs.position indiziiert ist sondern mit einer Integervariablen. Mit der könnte ich ja dann die einzelnen Zeilen ansprechen. Geht so etwas?

Jumpy 20. Jun 2013 16:41

AW: Werte aus dynamischen array löschen
 
Wie wär es denn mit Bauminas Vorschlag, "falsche" Werte gar nicht erst ins Array aufzunehmen?

Delphi-Quellcode:
   while stream.Position < stream.Size do begin
            stream.ReadBuffer(Digit, SizeOf(Digit));
            Spannung:= 10 * digit / 32768;
            time:=time+1/250;

            if not ((time > 0.1*x) and (time < 0.2*x)) then
              begin
              setlength(arr, High[arr]+2);
              arr[High[arr]].Zeit:=time;
              arr[High[arr]].U:=Spannung;
              end;

Uwe Raabe 20. Jun 2013 16:46

AW: Werte aus dynamischen array löschen
 
Ich kann dir leider immer noch nicht ganz folgen, aber trotzdem mal ein Versuch:

Delphi-Quellcode:
   
    StreamSize := Stream.Size;
    SetLength(arr, (StreamSize - Stream.Position) div Sizeof(digit));
    j := 0;
    time := 0;
    while Stream.Position < StreamSize do begin
      Stream.ReadBuffer(digit, SizeOf(digit));
      Spannung := 10 * digit / 32768;
      time := time + 1 / 250;
      inc(j);
      arr[j].Zeit := time;
      arr[j].U := Spannung;
    end;
Das Speichern von Stream.Size in einer lokalen Variablen soll verhindern, daß bei jedem Stream.Size zwei Seek-Anweisungen durchgeführt werden.

Nach der while-Schleife stehen erstmal alle Werte im Array, dessen Größe über Length(arr) abgefragt werden kann (bedenke: der höchste Index ist 1 weniger - alternativ kann man den auch mit High(arr) bekommen).

Wenn du nun einen bestimmten Zeitbereich aus dem Array löschen willst, solltest du ausnutzen, daß die Einträge zeitlich aufeinander folgen. Du musst also nur den Index des ersten und letzten (bzw. den danach) zu löschenden Eintrags finden. Dazu wird das Array einfach durchlaufen:

Delphi-Quellcode:
    idx1 := -1;
    idx2 := -1;
    for I := 0 to Length(arr) - 1 do begin
      if idx1 < 0 then begin
        if arr[I].Zeit > vonZeit then begin
          idx1 := I;
        end;
      end
      else if arr[I].Zeit > bisZeit then begin
        idx2 := I;
        Break;
      end;
    end;
    { idx1 gibt den ersten zu löschenden Eintrag an, idx2 den nach dem letzten zu löschenden }
Jetzt kann der entsprechende Bereich entfernt werden.

Delphi-Quellcode:
    if idx1 >= 0 then begin
      if (idx2 < 0) then begin
        { bis zum Ende löschen }
        SetLength(arr, idx1 - 1);
      end
      else begin
        Move(arr[idx2], arr[idx1], (idx2 - idx1)*Sizeof(arr[0]));
      end;
    end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:31 Uhr.

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