[fpc-pascal] sorting and merging array of records

Sven Barth pascaldragon at googlemail.com
Tue Jan 10 22:41:50 CET 2012


On 10.01.2012 22:02, waldo kitty wrote:
> On 1/10/2012 14:41, Sven Barth wrote:
>> On 10.01.2012 20:12, waldo kitty wrote:
>>> i don't know what this is pointing to because it is evidently not in my
>>> sources but in a unit i'm loading... the actual compiler message is
>>>
>>> (750,50) Error: Operator is not overloaded
>>> satsort.pas(434) Fatal: There were 1 errors compiling module, stopping
>>> satsort.pas(0) Fatal: Compilation aborted
>>>
>>
>> Oh damn it, I forgot about that.
>>
>> Is it possible for you to update to version 2.6? The problem is the
>> following:
>> the list I mentioned to you uses a equality operator ("=") of two
>> values of the
>> type you specialize with. Thus you need an overloaded operator in case of
>> records. But you can't use a global overloaded operator (which you
>> could do in
>> FPC 2.4.5), as the specialization will only see those types, functions
>> and
>> operators that were visible when the generic (the TFPGList) was
>> declared. So
>> you'll need to use advanced records for that (which are only available
>> from
>> 2.6.0 on).
>
> hummm... i may not need this specialization, then... i'm not comparing
> the entire record but portions of the fields in the records... i've made
> a few changes that should make this easier for me to do... let me show
> an example of an input record...

It's not about YOU comparing the entire record. The TFPGList uses that 
internally for it's own bookkeeping.

The specialization is mostly for type safety and ease of use. As I show 
you below a simple pointer based TList works as well (if you follow some 
advices). In the end it should be easier to handle than an array ;)

>
> ISS (Zarya)
> 1 25544U 98067A 11355.91136867 .00021672 00000-0 28116-3 0 6701
> 2 25544 51.6441 296.4760 0024445 190.7247 276.2995 15.58432251750217
>
>
> this breaks out like this...
>
> line columns example description
> 0 1-24 ISS (Zarya) common name
>
> 1 1 1 element line number
> 1 3-7 25545 catalog number
> 1 8 U elset classification
> 1 10-17 98067A international designator
> 1 19-32 11355.91136867 epoch (UTC)
> 1 34-43 .00021672 1st deriv of mean motion
> 1 45-52 00000-0 2nd deriv of mean motion
> 1 54-61 28116-3 B* drag term
> 1 63 0 element set type
> 1 65-68 670 element number
> 1 69 1 checksum
>
> 2 1 2 element line number
> 2 3-7 25545 catalog number
> 2 9-16 51.6441 orbit inclination
> 2 18-25 296.4760 rt ascension acend node
> 2 27-33 0024445 eccentricity
> 2 35-42 190.7247 arg of perigee (degrees)
> 2 44-51 276.2995 mean anomaly (degrees)
> 2 53-63 15.58432251 mean motion (revs/day)
> 2 64-68 75021 rev number at epoch
> 2 69 3 checksum
>
>
> so i now have the following to define the record... since i only need
> the catalog number to check for duplicates and the epoch to determine
> which one to keep, i've added those two fields to the record and pull
> them during the reading of the data (see Input_Satellite_List procedure
> below)...

Wouldn't it be easier for you to parse the complete two lines into a 
full blown record (just asking). Then you don't need to parse them later 
on and can just do a "YourRecord.MeanAnomaly" (for example). Using a 
TStringList with the correct parameters can also remove the burden from 
you to seperate the values by hand.

>
> Function IsSameReal(num1,num2 : double) : integer;
>
> begin
> if (num1 < num2) then IsSameReal := -1
> else
> if (num1 = num2) then IsSameReal := 0
> else
> if (num1 > num2) then IsSameReal := 1;
> end;

You can shorten this by using the "CompareValue" function from unit "Math":

function IsSameReal(num1,num2: Double): Integer;
begin
   IsSameReal := CompareValue(num1, num2);
end;

(though I would name that function CompareReal instead of IsSameReal ;) )

> i'm not sure where the equality operator you speak of above comes from
> or why i need it in play :/
>

It's inside the implementation of TFPGList. I don't remember exactly 
where, but it's used in there.

> something else i need to make sure of is that this will compile on my
> OS/2 FPC 2.4.2 since that is the environment it will be under when it
> goes production... unless, of course, there's a shiney new
> 0s2260full.zip file for me to play with ;)
>
[...]
>
> as i wrote in another message, my windows' boxen update from SVN and
> every time i've tried to update FPC and make whatever, it breaks and i'm
> scared to break what i currently have working... i always have to blow
> the directory away, then svn it all back down, and then do the make
> thing... the ugly part is that i also have lazarus built with and using
> this svn'd version of FPC so i definitely do not want to be breaking
> that, either...
>
> a second reason is i don't do the svn thing on the OS/2 box and so have
> to rely on an install package for that OS... the last time i did this, i
> unzipped os2242full.zip to /fpc and went from there... i recall having
> to manually configure a lot of stuff, though... include paths and the
> like... i still don't have the help working properly in any environment
> which greatly hampers things :/

You'll need to ask Tomas Hajny then as he is the one who is most 
familiar with OS/2. But there seems to indeed be a os2260full.zip at 
SourceForge :) (So it might be worthwhile to investigate in an update, 
not only because of generics ;) )

>> 2. You can then use the TList which is based on pointers (and requires
>> a bit
>> manual housekeeping, but I can help you here as well if you want)
>
> TList? hummm... better? smaller? faster? easier to use? small memory
> footprint? i'm game to try things as long as it works in the end ;)

TList is basically an array wrapped in a class (though I would suggest 
TFPList as that is faster than TList (TList is based on TFPList)). Both 
can be found in unit Classes.

The following you need to know: T(FP)List works on pointers, thus you 
need to
1. declare a pointer type to your record type (e.g. Pthree_line_data = 
^three_line_data)
2. allocate a Pthree_line_data variable if you want to add a new entry 
to the list

E.g.
Procedure Input_Satellite_List(var aInputFile: TextFile);

var
   data : Pthree_line_data;
   ...
begin
   if not EOF(aInputFile) then
   begin
     New(data); // <= allocate the data
     ...
     data^.catnbr := ... // you must dereference the pointer using "^" 
to access the fields
     ...
     aList.Add(data);
   end;
end;

3. if you remove an entry from the list you need to dispose the entry:

E.g.

procedure SomeProcWhichMightRemoveAEntry(aList: TList { or TFPList });
begin
   ...
   Dispose(Pthree_line_data(aList[IndexToDelete])); // the cast is 
necessary for "Dispose" to work correctly
   ...
end;

4. If you work with a list entry you need to cast it to your pointer 
type (either using a cast like above in the Dispose or by declaring a 
local variable which will hold a casted variant)

E.g.

procedure SomeProcWhichWorksWithEntry(aList: TList { or TFPList });
var
   data: Pthree_line_data;
begin
   ...
   // variant 1
   Pthree_line_data(aList[IndexToWorkWith])^.catnbr := ...
   // or
   if Pthree_line_data(aList[IndexToWorkWith])^.catnbr = ... then
   ...
   // variant 2
   data := Pthree_line_data(aList[IndexToWorkWith]);
   data^.catnbr := ...
   // or
   if data^.catnbr = ... then
   ...
end;

Variant 2 might be preferable if you often access the element after each 
other.

5. At the end of the list's lifetime you need to Dispose all items (or 
before you clear the list)

E.g.

for i := 0 to aList.Count - 1 do
   Dispose(Pthree_line_data(aList[i]));
aList.Clear; // or aList.Free depending on the context

I hope this helps you along, but feel free to ask more if you need help. :)

Regards,
Sven



More information about the fpc-pascal mailing list