Lazarus

Programming => General => Topic started by: imekon on August 18, 2019, 03:28:29 pm

Title: Trying to copy part of an array
Post by: imekon on August 18, 2019, 03:28:29 pm
Why does this return a substring:

Code: Pascal  [Select]
  1. procedure TGraphic.AddTriangles(points: array of single);
  2. var
  3.   i: integer;
  4.   triangle: TTriangle;
  5.   chunk: array of single;
  6.  
  7. begin
  8.   i := 0;
  9.   while i < Length(points) - 1 do
  10.   begin
  11.     triangle := TTriangle.Create;
  12.     chunk := Copy(points, i, 9);     // HERE!
  13.     triangle.SetPoints(chunk);
  14.     inc(i, 9)
  15.   end;
  16. end;
  17.  

The error I get is:

Error: Incompatible types: got "ShortString" expected "{Dynamic} Array Of Single"

triangle.SetPoints expects array of single, why does Copy convert an array of single to shortstring?
Title: Re: Trying to copy part of an array
Post by: imekon on August 18, 2019, 03:33:25 pm
Here's a complete program showing the issue:

Code: Pascal  [Select]
  1. program test;
  2.  
  3. var
  4.   i: integer;
  5.   thing: array [1..9] of single;
  6.   slice1: array of single;
  7.  
  8. begin
  9.   for i := 1 to 9 do
  10.     thing[i] := i * 2.1;
  11.  
  12.   slice1 := Copy(thing, 1, 3);
  13. end.
  14.  

test.lpr(12,13) Error: Incompatible types: got "ShortString" expected "{Dynamic} Array Of Single"
Title: Re: Trying to copy part of an array
Post by: Thaddy on August 18, 2019, 03:45:51 pm
The syntax is here: https://www.freepascal.org/docs-html/rtl/system/slice.html
simple example:
Code: Pascal  [Select]
  1. procedure ShowArray(const A: array of single);
  2. var
  3.   i: single;
  4. begin
  5.   for i in a do
  6.     WriteLn(i:2:2);
  7. end;
  8.  
  9. begin
  10.   ShowArray(Slice([1,2,3,4],2));
  11. end.


Title: Re: Trying to copy part of an array
Post by: julkas on August 18, 2019, 04:19:05 pm
Code: Pascal  [Select]
  1. program test;
  2. {$mode delphi}
  3. var
  4.   i: integer;
  5.   thing: array [1..9] of single;
  6.   slice: array of single;
  7. begin
  8.   for i := 1 to 9 do
  9.     thing[i] := i;
  10.   SetLength(slice, 9);
  11.   Move(thing[1], slice[0], 9*SizeOf(single));
  12.   for i := 1 to 9 do
  13.     WriteLn(slice[i-1])
  14. end.
  15.  
Title: Re: Trying to copy part of an array
Post by: Thaddy on August 18, 2019, 04:33:01 pm
Code: Pascal  [Select]
  1. program test;
  2. {$mode delphi}
  3. var
  4.   i: integer;
  5.   thing: array [1..9] of single;
  6.   slice: array of single;
  7. begin
  8.   for i := 1 to 9 do
  9.     thing[i] := i;
  10.   SetLength(slice, 9);
  11.   Move(thing[1], slice[0], 9*SizeOf(single));
  12.   for i := 1 to 9 do
  13.     WriteLn(slice[i-1])
  14. end.
  15.  
Sigh. we have Slice() as I demonstrated. It is also more efficient. It is built-in. No need to jump through hoops.
First check, then answer.
Title: Re: Trying to copy part of an array
Post by: julkas on August 18, 2019, 04:55:09 pm
Code: Pascal  [Select]
  1. program test;
  2. {$mode delphi}
  3. var
  4.   i: integer;
  5.   thing: array [1..9] of single;
  6.   slice: array of single;
  7. begin
  8.   for i := 1 to 9 do
  9.     thing[i] := i;
  10.   SetLength(slice, 9);
  11.   Move(thing[1], slice[0], 9*SizeOf(single));
  12.   for i := 1 to 9 do
  13.     WriteLn(slice[i-1])
  14. end.
  15.  
Sigh. we have Slice() as I demonstrated. It is also more efficient. It is built-in. No need to jump through hoops.
First check, then answer.
It's just my working solution.
BTW. Move() must be fast and host, OS optimized just as C memmove().
Title: Re: Trying to copy part of an array
Post by: Thaddy on August 18, 2019, 05:21:46 pm
It's just my working solution.
BTW. Move() must be fast and host, OS optimized just as C memmove().
Fine with me but Slice() is a compiler intrinsic and therefor should be faster.
Also note Slice() has been part of the Pascal language for *a*very*long*time* ...(.although the implementation in FPC is rather recent, give a couple of 10 years, I mean)

Note slice() still needs an open array parameter, in all other cases use copy. (But that was not the case here...)
Title: Re: Trying to copy part of an array
Post by: avk on August 18, 2019, 05:41:36 pm
It seems that if triangle.SetPoints could accept an open array, then copying could be completely avoided:
Code: Pascal  [Select]
  1. procedure AddTriangles(points: array of single);
  2. var
  3.   i: integer;
  4.   triangle: TTriangle;
  5. begin
  6.   i := 0;
  7.   while i <= Length(points) - 9 do
  8.     begin
  9.       triangle := TTriangle.Create;
  10.       triangle.SetPoints(points[I..I+8]);
  11.       inc(i, 9)
  12.     end;
  13. end;  
  14.  
Title: Re: Trying to copy part of an array
Post by: jamie on August 18, 2019, 05:46:02 pm
Or you could simply write yourself a Copy Function that works the same way as the string Copy does.

Code: Pascal  [Select]
  1. function Copy(Const A:Array of Single;aStart:Integer;ACount:Integer=1):TSingleArray;
  2. var
  3.   I:Integer;
  4. Begin
  5.   SetLength(result, 0);
  6.   If (Not AStart in [0..High(A)])or(Acount <= 0) then Exit;
  7.   If ACount+AStart > Length(A) Then ACount := Length(A)-AStart;
  8.   SetLength(Result, ACount);
  9.   For I:= 0 To ACount-1 do Result[I] := A[AStart+I];
  10. End;                                                    
  11.  

That will start you in any location within the Array and then you specify the number of elements from that point on.
 it returns an array created to the resolving size..

This will also test for limit control and not exceed the given array and simply return the remainder or nothing if it's outside the limits.

Title: Re: Trying to copy part of an array
Post by: Thaddy on August 18, 2019, 07:35:16 pm
Or you could simply write yourself a Copy Function that works the same way as the string Copy does.
Jamie! slice()! >:D
Is that feature so obscure everybody fails to comprehend it.... <sigh> and that goes for all of you...
Title: Re: Trying to copy part of an array
Post by: jamie on August 18, 2019, 07:40:38 pm
Or you could simply write yourself a Copy Function that works the same way as the string Copy does.
Jamie! slice()! >:D
Is that feature so obscure everybody fails to comprehend it.... <sigh> and that goes for all of you...

Please show me how you use Slice with a starting index and count?

from what I see, it's only starts at 0 and count is all you can specify..

The user was looking for a start index and count.
Title: Re: Trying to copy part of an array
Post by: Abelisto on August 18, 2019, 07:47:34 pm
Or you could simply write yourself a Copy Function that works the same way as the string Copy does.
Jamie! slice()! >:D
Is that feature so obscure everybody fails to comprehend it.... <sigh> and that goes for all of you...

Additionally, citation from your link: "but this array is not assignment compatible to any other array, and can therefor only be used in open array arguments to functions."
So it is impossible to use slice() function in a construction like
Code: Pascal  [Select]
  1. a := slice(b, c);
Title: Re: Trying to copy part of an array
Post by: Thaddy on August 18, 2019, 08:17:04 pm
Additionally, citation from your link: "but this array is not assignment compatible to any other array, and can therefor only be used in open array arguments to functions."
So it is impossible to use slice() function in a construction like
Code: Pascal  [Select]
  1. a := slice(b, c);
Can you explain what you mean? Of course that is possible. That's part of my demo .The devil is in the detail.
Title: Re: Trying to copy part of an array
Post by: imekon on August 18, 2019, 08:36:24 pm
Or you could simply write yourself a Copy Function that works the same way as the string Copy does.

Code: Pascal  [Select]
  1. function Copy(Const A:Array of Single;aStart:Integer;ACount:Integer=1):TSingleArray;
  2. var
  3.   I:Integer;
  4. Begin
  5.   SetLength(result, 0);
  6.   If (Not AStart in [0..High(A)])or(Acount <= 0) then Exit;
  7.   If ACount+AStart > Length(A) Then ACount := Length(A)-AStart;
  8.   SetLength(Result, ACount);
  9.   For I:= 0 To ACount-1 do Result[I] := A[AStart+I];
  10. End;                                                    
  11.  

That will start you in any location within the Array and then you specify the number of elements from that point on.
 it returns an array created to the resolving size..

This will also test for limit control and not exceed the given array and simply return the remainder or nothing if it's outside the limits.

This looks like what I'm looking for, thanks!
Title: Re: Trying to copy part of an array
Post by: avk on August 18, 2019, 08:50:57 pm
Or you could simply write yourself a Copy Function that works the same way as the string Copy does...
Hmm, I can only envy the Delphi programmers, for some reason they always have the fastest processors, unlimited memory and the most understandable code.
Title: Re: Trying to copy part of an array
Post by: Thaddy on August 18, 2019, 08:52:59 pm
Or you could simply write yourself a Copy Function that works the same way as the string Copy does...
Hmm, I can only envy the Delphi programmers, for some reason they always have the fastest processors, unlimited memory and the most understandable code.
You just killed me with laughter..... ;D ;D
Title: Re: Trying to copy part of an array
Post by: Abelisto on August 18, 2019, 09:56:44 pm
Additionally, citation from your link: "but this array is not assignment compatible to any other array, and can therefor only be used in open array arguments to functions."
So it is impossible to use slice() function in a construction like
Code: Pascal  [Select]
  1. a := slice(b, c);
Can you explain what you mean? Of course that is possible. That's part of my demo .The devil is in the detail.

I mean what I mean (or, precisely, what documentation mean): result of function slice() is can not be assigned to any variable.

Probably I completely lost, but which demo you are talking about? I see only the code snippets from the doc.

Very simple test:

Code: Pascal  [Select]
  1. type
  2.     TArraySingleDyn = array of single;
  3.     TArraySingleFixed = array[1..4] of single;
  4. var
  5.     ad: TArraySingleDyn;
  6.     af: TArraySingleFixed;
  7. begin
  8.     ad := slice(ad, 3);
  9.     ad := slice(af, 3);
  10. end.

And compilation result:
Code: [Select]
Free Pascal Compiler version 3.3.1-r42722 [2019/08/17] for x86_64
Copyright (c) 1993-2019 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling test.pas
test.pas(8,16) Error: SLICE cannot be used outside of parameter list
test.pas(9,16) Error: SLICE cannot be used outside of parameter list
test.pas(11) Fatal: There were 2 errors compiling module, stopping
Fatal: Compilation aborted

That is what I mean.
Title: Re: Trying to copy part of an array
Post by: jamie on August 18, 2019, 11:15:28 pm
Arguing with Thaddy is like a battle of wits, I just hate fighting an unarmed person.

Title: Re: Trying to copy part of an array
Post by: jamie on August 18, 2019, 11:47:56 pm
I've never had much interest for generics in general because I think they are highly over rated however, in this case they could work out well using them for the Copy function I posted to change the different types as needed in code. This should only compile the functions with the types requested.
Title: Re: Trying to copy part of an array
Post by: winni on August 19, 2019, 12:00:37 am
@Abelisto

If slice should be used, you get around the problem with slice result only as parameter that way:

Code: Pascal  [Select]
  1. Type ArrayOfSingle = array of single;
  2.  
  3. function singleS ( s : array of single) : ArrayOfSingle;
  4. begin
  5. setLength(result,length(s));
  6. for i := 0 to high (s) do result[i] := s[i];
  7. end;
  8.  
  9.  
  10. MyArray := SingelS (slice (InArray, 23));
  11.  
  12.  

That's another solution. Which is quicker I don't know

Winni
Title: Re: Trying to copy part of an array
Post by: PascalDragon on August 19, 2019, 09:37:13 am
Why does this return a substring:

Code: Pascal  [Select]
  1. procedure TGraphic.AddTriangles(points: array of single);
  2. var
  3.   i: integer;
  4.   triangle: TTriangle;
  5.   chunk: array of single;
  6.  
  7. begin
  8.   i := 0;
  9.   while i < Length(points) - 1 do
  10.   begin
  11.     triangle := TTriangle.Create;
  12.     chunk := Copy(points, i, 9);     // HERE!
  13.     triangle.SetPoints(chunk);
  14.     inc(i, 9)
  15.   end;
  16. end;
  17.  

The error I get is:

Error: Incompatible types: got "ShortString" expected "{Dynamic} Array Of Single"

triangle.SetPoints expects array of single, why does Copy convert an array of single to shortstring?

Copy only supports strings and dynamic arrays, but not static or open array. So if you don't rely on AddTriangles to have an open array as parameter you can use this:

Code: Pascal  [Select]
  1. type
  2.   TSingleArray = array of Single;
  3.  
  4. procedure TGraphic.AddTriangles(points: TSingleArray);
  5. var
  6.   i: integer;
  7.   triangle: TTriangle;
  8.   chunk: TSingleArray;
  9.  
  10. begin
  11.   i := 0;
  12.   while i < Length(points) - 1 do
  13.   begin
  14.     triangle := TTriangle.Create;
  15.     chunk := Copy(points, i, 9);     // HERE!
  16.     triangle.SetPoints(chunk);
  17.     inc(i, 9)
  18.   end;
  19. end;

The main difference regarding open and dynamic array is that you can't call AddTriangles like this if you use a dynamic array:
Code: Pascal  [Select]
  1. AddTriangle([4.5452, 2.4523, 1.5342]);
You have to use a dynamic array variable instead.

However with 3.2 and newer that works due to the dynamic array constructors.