Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi How to reverse array of any type? (https://www.delphipraxis.net/171924-how-reverse-array-any-type.html)

WojTec 2. Dez 2012 15:05

Delphi-Version: 7

How to reverse array of any type?
 
Hi, is possible to reverse (I actually need this, but I mean processing in any way) array of any type (numbers, string, booleans, etc.) by one procedure?

Furtbichler 2. Dez 2012 18:18

AW: How to reverse array of any type?
 
By 'reverse' you mean: ABCD => DCBA?

Well, that's simple: All you need is the Address of the first element, the size of an element and the total number of elements (n), then you exchange elements 0 with n-1, 1 with n-2 and so on. To exchange an element you will need a temporary storage of ElementSize Bytes.

The signature of the function could be:
Delphi-Quellcode:
Procedure SwapArrayElements(aStartElement : Pointer; aElementSize, aElementCount : Integer);

uligerhardt 2. Dez 2012 18:36

AW: How to reverse array of any type?
 
That is what generics are for, but they are available only from Delphi 2009 and up.

WojTec 2. Dez 2012 18:44

Re: How to reverse array of any type?
 
Exactly, you are correct!

I thought about pointers, but I don't know how to access fields? :(

AData: Pointer
Inc(AData) - to get next one, usage not possible :(

jaenicke 2. Dez 2012 19:02

AW: How to reverse array of any type?
 
As you have Delphi 2010 in your profile, generics should be not problem, are they?
Delphi-Quellcode:
  TArrayUtil = class
  public
    class procedure Swap<T>(var Value1, Value2: T);
    class procedure Reverse<T>(var Value: array of T);
  end;

{ TArrayUtil }

class procedure TArrayUtil.Reverse<T>(var Value: array of T);
var
  i: Integer;
begin
  if Length(Value) > 0 then
    for i := Low(Value) to High(Value) div 2 do
      Swap<T>(Value[i], Value[High(Value) - i]);
end;

class procedure TArrayUtil.Swap<T>(var Value1, Value2: T);
var
  Temp: T;
begin
  Temp := Value1;
  Value1 := Value2;
  Value2 := Temp;
end;
Example usage:
Delphi-Quellcode:
var
  Test: array of Integer;
  i: Integer;
begin
  SetLength(Test, 0);
  for i := Low(Test) to High(Test) do
    Test[i] := i;
  TArrayUtil.Reverse<Integer>(Test);
  for i := Low(Test) to High(Test) do
    ShowMessage(IntToStr(Test[i]));
end;
// EDIT:
Of course it would be faster to swap directly in procedure Reverse.

// EDIT2:
Ok, translated to English and I did not see Delphi version 7 in the post. Then this won't work.

uligerhardt 2. Dez 2012 19:25

AW: How to reverse array of any type?
 
Zitat:

Zitat von jaenicke (Beitrag 1194030)
Da bei dir Delphi 2010 steht

Im Post selbst steht D7.

WojTec 2. Dez 2012 19:39

Re: How to reverse array of any type?
 
Ok, nice, nice, but how to access array elements if parameter is Pointer only? Array can be in any type.

uligerhardt 2. Dez 2012 19:58

AW: Re: How to reverse array of any type?
 
Zitat:

Zitat von WojTec (Beitrag 1194035)
Ok, nice, nice, but how to access array elements if parameter is Pointer only? Array can be in any type.

What is a pointer? The parameter to your routine or the array element?

WojTec 2. Dez 2012 20:04

Re: How to reverse array of any type?
 
Pointer is procedure parameter (see @Furtbichler post).

uligerhardt 2. Dez 2012 20:17

AW: Re: How to reverse array of any type?
 
Zitat:

Zitat von WojTec (Beitrag 1194035)
Ok, nice, nice, but how to access array elements if parameter is Pointer only? Array can be in any type.

With Furtbichler's routine signature you could have something like
Delphi-Quellcode:
procedure SwapArrayElements(aStartElement : Pointer; aElementSize, aElementCount : Integer);
var
  p: PByte;
begin
  p := AStartElement; // p points to first element
  Inc(p, aElementSize); // Now p points to second element
  Move(p^, ..., aElementSize); // Moves the element p points to
end;
(NB: These are only some building blocks of the routine, not the whole thing. :mrgreen:)

himitsu 3. Dez 2012 03:47

AW: Re: How to reverse array of any type?
 
I submitted an expansion proposal at Embarcadero.
http://qc.embarcadero.com/wc/qcmain.aspx?d=110391
You may like to vote for it, so it will soon be integrated.
For all Delphi versions from 2009, you can upgrade this as a class helper.

Otherwise, these methods can of course also copy out and use directly.
Zitat:

Delphi-Quellcode:
procedure SwapArrayElements(aStartElement: Pointer; aElementSize, aElementCount: Integer);

Or you get the necessary information about the RTTI/TypeInfo.
Delphi-Quellcode:
procedure SwapArrayElements(var TheArray; ArrTypeInfo: Pointer);

var MyArr: array of ...;
SwapArrayElements(MyArr, TypeInfo(MyArr));

WojTec 3. Dez 2012 10:43

Re: How to reverse array of any type?
 
Delphi-Quellcode:
procedure ReverseArray(AData: Pointer; const ASize, ACount: Integer);
var
  Left, Right, Temp: Integer;
  P: PCardinal;
begin
  P := AData;

  Left := 0;
  Right := ACount;

  Result := Left < Right;

  if Result then
  begin
    while (Left < Right) do
    begin
      {Temp := AValues[Left];
      AValues[Left] := AValues[Right];
      AValues[Right] := Temp;}  // Don't know how to exchange with pointers :(
      //Move(P^, ..., ASize); // Don't know how if I don't know types ????????

      Inc(P);
      Inc(Left);
      Dec(Right);
    end;
  end;
end;
I don't know how replace part should works. Above is form reversing knowed type array. :(

Medium 3. Dez 2012 11:04

AW: How to reverse array of any type?
 
You need to understand, that you can not operate in a array-like fashion anymore, if you want a fully generic function. You have to go down an abstraction layer, and work on the actual memory.
An array simply is a sequence of values written behind each other in memory. Every element has a length (in bytes), but the length will be determined by the data type in the array. You employ pointer operations instead of the compiler magic (pascal arrays) to gain the possibility to work with data of arbitrary size. Without Generics, there just is no other way. So instead of array indexes, you point to elements using a memory address and the size of the elements. Traversing one element ahead "increase index by 1" then becomes "take pointer of the current element, and add the element-size to it". Copying "myArray[i] := myArray[m]" becomes a raw memory move-operation "Move(DestinationPointer, SourcePointer, ElementSizeInBytes)". As long as you have anything with square brackets "[]" in your reverse-function, you can be sure to think too high-level ;)

WojTec 3. Dez 2012 11:17

Re: How to reverse array of any type?
 
Yes yes, I know ;) So I'm asking how to do it? Because I don't know how do it on pointers only? :(

BTW: @himitsu I voted for your extended TArray :)

uligerhardt 3. Dez 2012 13:16

AW: Re: How to reverse array of any type?
 
Zitat:

Zitat von WojTec (Beitrag 1194088)
Delphi-Quellcode:
procedure ReverseArray(AData: Pointer; const ASize, ACount: Integer);
var
  Left, Right, Temp: Integer;
  P: PCardinal;
begin
  P := AData;

  Left := 0;
  Right := ACount;

  Result := Left < Right;

  if Result then
  begin
    while (Left < Right) do
    begin
      {Temp := AValues[Left];
      AValues[Left] := AValues[Right];
      AValues[Right] := Temp;}  // Don't know how to exchange with pointers :(
      //Move(P^, ..., ASize); // Don't know how if I don't know types ????????

      Inc(P);
      Inc(Left);
      Dec(Right);
    end;
  end;
end;
I don't know how replace part should works. Above is form reversing knowed type array. :(

Don't use
Delphi-Quellcode:
PCardinal
and
Delphi-Quellcode:
Inc(P)
because this would limit you to elements with the same size as Cardinal: if
Delphi-Quellcode:
P
is of type
Delphi-Quellcode:
PCardinal
, then it points to an element of
Delphi-Quellcode:
SizeOf(Cardinal)
bytes. If you then do
Delphi-Quellcode:
Inc(P)
you advance
Delphi-Quellcode:
P
by
Delphi-Quellcode:
SizeOf(Cardinal)
bytes. But you want
Delphi-Quellcode:
P
to point to elements of size
Delphi-Quellcode:
ASize
bytes, so use
Delphi-Quellcode:
PByte
and
Delphi-Quellcode:
Inc(P, ASize)
(as I already wrote :stupid:).

himitsu 3. Dez 2012 13:25

AW: Re: How to reverse array of any type?
 
:?:
Delphi-Quellcode:
procedure ReverseArray(AData: Pointer; const ASize, ACount: Integer);
var
  Temp: array of Byte;
  Data: PAnsiChar absolute AData; // PAnsiChar verfügt über Zeiger-Arithmetik
  i, j: Integer;
begin
  SetLength(Temp, ASize);
  i := ACount div 2 - 1;
  while i >= 0 do begin
    j := ACount - i - 1;
    Move(Data[i * ASize], Temp[0], ASize);
    Move(Data[j * ASize], Data[i * ASize], ASize);
    Move(Temp[0], Data[j * ASize], ASize);
    Dec(i);
  end;
end;

WojTec 3. Dez 2012 13:29

Re: How to reverse array of any type?
 
Thanks :) Now I'll try to transform Shuffle() in this way :D


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:23 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