Jump to content
skyzoframe[hun]

How can I use pointers to access the value of a dmArray = TList<dmRecord> record?

Recommended Posts

Greetings everyone,

I want to sort a tList with some kind of record parameter. Somehow I need to use pointers to get to the record without using the name of the record.

In this example I am using the name "Rec.x". However, in the future I would like to use "Rec.y", "Rec.z","Rec.ID" or any other record value in the sort. // See below

In fact, I have never used pointers before.

 

"function Foo.BubbleSort(AList: dmA00; SomeParameterHere:IsSomething ;out Error: String): Boolean;"

...

" if jRec.SomeParameterHere > j1Rec.SomeParameterHere then"

 

kind regards Zoltan.K

 

  type
    dmR00 = Record
      ID : integer;
      x,y,z : integer;
    End;
...
dmA00 = TList<dmR00>;
...
  
function Foo.BubbleSort(AList: dmA00; out Error: String): Boolean;
  var
    jRec, j1Rec: dmR00;
    i,j : integer;
begin
  try
    for i := 0 to AList.Count - 2 do
    begin
      for j := 0 to AList.Count - 2 - i do
      begin
        // clear record
        jRec  :=  default(dmR00);
        j1Rec  :=  default(dmR00);
        // fill record
        jRec := aList[j];
        j1Rec := aList[j+1];
        // check record
        if jRec.x > j1Rec.x then
        begin
          AList[j] := j1Rec;
          AList[j + 1] := jRec;
        end;
      end;
    end;
    Result := True; 
  except
  on E: Exception do
    begin
      Error := ('Exception class name = ' + E.ClassName + sLineBreak +
        'Exception message = ' + E.Message);
      Result := False;
    end;
  end;
end;  

 

Share this post


Link to post

It's not clear to me what exactly you are doing but you can use TList<T>.List to get access to the internal dynamic array of TList<T>. From there you can create a pointer to the individual elements in the array:

type
  TMyRecord = record
    Foo: integer;
    Bar: string;
  end;

  PMyRecord = ^TMyRecord;

begin
  var MyList := TList<TMyRecord>.Create;
  ...

  // Get a reference to the internal dynamic array.
  // Note that this reference, and any pointers to the elements in
  // it, are only valid as long as the list size remains static;
  // Once you clear the list or add items to it, the references are 
  // stale becuase the internal array can be reallocated.
  var Items := MyList.List;
    
  // Get a pointer to an element in the array
  var SomeItem: PMyRecord := @Items[0];
  
  // Clear the element
  SomeItem^ := Default(TMyRecord);
  
  // Modify the element
  SomeItem.Foo := 42;
  SomeItem.Bar := 'Hello world';
end;

 

I assume your bubble sort is just an example. Otherwise, use TList<T>.Sort to sort the list.

 

Edited by Anders Melander
  • Like 1

Share this post


Link to post

Yes, it is just an example.

 

I wanted to get to the record-element. With the help of pointers. But it is not clear to me how to do it. I have no idea if it will be possible.
Alternative solution can be a key-parameter, and each sorting record element I can handle with case statement.

 

 

type
    dmR00 = Record
      	ID : integer;//key-0
      	x,//key-1
      	y,//key-2
      	z : integer;//key-3
    End;
...
dmA00 = TList<dmR00>;
...
  
function Foo.BubbleSort(AList: dmA00; key:byte; out Error: String): Boolean;
  var
    jRec, j1Rec: dmR00;
    i,j : integer;
begin
  try
    for i := 0 to AList.Count - 2 do
    begin
      for j := 0 to AList.Count - 2 - i do
      begin
        // clear record
        jRec  :=  default(dmR00);
        j1Rec  :=  default(dmR00);
        // fill record
        jRec := aList[j];
        j1Rec := aList[j+1];
        // check record
  
        case key of
          0: begin
          if jRec.ID > j1Rec.ID then
            begin
              AList[j] := j1Rec;
              AList[j + 1] := jRec;
            end;
          end;
          1: begin
          if jRec.x > j1Rec.x then
            begin
              AList[j] := j1Rec;
              AList[j + 1] := jRec;
            end;
          end;
          2: begin
          if jRec.y > j1Rec.y then
            begin
              AList[j] := j1Rec;
              AList[j + 1] := jRec;
            end;
          end;
          3: begin
          if jRec.z > j1Rec.z then
            begin
              AList[j] := j1Rec;
              AList[j + 1] := jRec;
            end;
          end;
        end;
  	  end;
    end;
    Result := True; 
  except
  on E: Exception do
    begin
      Error := ('Exception class name = ' + E.ClassName + sLineBreak +
        'Exception message = ' + E.Message);
      Result := False;
    end;
  end;
end;  

 

 

 

 

 

 

 

 

Share this post


Link to post
3 hours ago, skyzoframe[hun] said:

Greetings everyone,

I want to sort a tList with some kind of record parameter. Somehow I need to use pointers to get to the record without using the name of the record.

In this example I am using the name "Rec.x". However, in the future I would like to use "Rec.y", "Rec.z","Rec.ID" or any other record value in the sort. // See below

In fact, I have never used pointers before.

 

"function Foo.BubbleSort(AList: dmA00; SomeParameterHere:IsSomething ;out Error: String): Boolean;"

...

" if jRec.SomeParameterHere > j1Rec.SomeParameterHere then"

 

kind regards Zoltan.K

 

 

A TList<T> has a constructor overload that takes a comparer (IComparer<T> instance) to use for sorting and searching the list by default. The Sort method also has such an overload. You use

TComparer<T>.Construct() 

to fabricate a suitable comparer on the fly, providing an anonymous method that does the actual comparison of two items in the way you want the sort to go. This anonymous method has to "know" the record type in question, so you can directly refer to the fields of the two items passed to it.

 

Forget about pointers, you do not need them to work with generics.

  • Like 1

Share this post


Link to post
2 hours ago, PeterBelow said:

Forget about pointers, you do not need them to work with generics.

Maybe not in this case but when you have lists or arrays of records it is most often much more efficient to pass a pointer around than to copy the records back and forth.

 

4 hours ago, skyzoframe[hun] said:

I wanted to get to the record-element. With the help of pointers. But it is not clear to me how to do it. I have no idea if it will be possible.

I just showed you exactly how it's done.

 

 

If this is performance sensitive, there are a lot of entries in the list and the records are large, then an alternative is to have the data in one list and an index into the list in another list TList<integer> or array TArray<integer>. Then you use the record list to hold the data and when you need to sort the data you just sort the index list/array. To access the data in sort order you must then use the sorted index list to get the index of the data in the record list. It's very easy but a bit hard to explain without a whiteboard.

 

Anyway, forget about that for now. If you just want to sort the list on different record fields you can do so by passing a custom comparer to the Sort method, as Peter mentioned:

type
  TMyRecord = record
    Foo: integer;
    Bar: string;
  end;

  TMyList = TList<TMyRecord>;

  TMyField = (mfFoo, mfBar);

procedure SortList(List: TMyList; Field: TMyField);
begin
  var Comparer: IComparer<TMyRecord>;

  case Field of
    mfFoo:
      Comparer := TComparer<TMyRecord>.Construct(
        function(const A, B: TMyRecord): integer
        begin
          Result := (A.Foo - B.Foo);
        end);

    mfBar:
      Comparer := TComparer<TMyRecord>.Construct(
        function(const A, B: TMyRecord): integer
        begin
          Result := CompareText(A.Bar, B.Bar);
        end);

  else
    exit;
  end;

  List.Sort(Comparer);
end;

 and to use the above:

begin
  var MyList := TList<TMyRecord>.Create;
    
  ...populate the list...

  // Sort the list on the "Foo" field.
  SortList(MyList, mfFoo);
    
  // Sort the list on the "Bar" field.
  SortList(MyList, mfBar);
    
  ...etc...
end;

 

  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×