Sorting collections at runtime
Posted: Fri Aug 07, 2009 11:13 am
by Craig Shearer >> Mon, 8 Feb 1999 23:09:11 GMT
Hello All
I've been doing some experiments on sorting an array at runtime. The basic requirement is to have an array of objects and sort the objects in the array according to one or more of their properties, kind of like specifiying the keys for a member key dictionary at runtime. This sort of thing is very useful where users want to specify the order of records in their reports etc.
Anyway, since JADE lacks such a feature I thought I'd have a go at implementing this using the extractSort method on the File class.
I added a method to the ObjectArray class to sort its contents. The method takes a collection of SortKey objects (of my own devising) which basically store the name of the property on the class, the length, whether or not the key is numeric and whether or not the key should be sorted ascending or descending.
The idea is that each object in the array gets its key values written to the file, along with its Oid so that it can be identified on the way back in. The file is sorted, then the collection cleared, then the collection is re-populated from the sorted file.
Thus, all the objects in the collection will magically appear sorted.
The reason for this post is that the performance (as you can imagine) isn't very good. Here's the details:
Sort of a collection with 1 key containing 2000 objects takes about 8 seconds - pretty bad. However, when the actual parts of the sorting are broken down, the file sort actually only takes about 1/2 a second (much more respectable). It's the writing and reading the file that takes the time.
So, what I would propose is that JADE have a feature that allows this sorting to happen WITHOUT having to write objects out to a file.
Here's the code, in case you want to try it yourself. There are various things you'd need to do to make it work in your environment (like creating the SortKey and SortKeyArray classes, and implementing a getTempFileName method on app).
sort(sortKeys: SortKeyArray) lockReceiver, updating;
vars
sortSrc,
sortDest : File;
srcFileName,
destFileName : String;
actor : SortActor;
actors : SortActorArray;
sortKey : SortKey;
pos,
fieldNum,
keyStart,
oidPosition : Integer;
obj : Object;
oid,
line : String;
propValue : Any;
propString : String;
i : Integer;
begin
create sortSrc transient;
srcFileName := app.getTempFileName("srt",0);
sortSrc.fileName := srcFileName;
sortSrc.recordSize := 0;
sortSrc.endOfLine := CrLf;
create sortDest transient;
destFileName := app.getTempFileName("srt",0);
sortDest.fileName := destFileName;
sortDest.allowReplace := true;
sortDest.allowCreate := true;
create actors transient;
actors.kway := 3;
// create the SortActor objects
keyStart := 1;
fieldNum := 1;
foreach sortKey in sortKeys do
create actor;
actor.numeric := sortKey.fNumeric;
actor.length := sortKey.fLength;
actor.startPosition := keyStart;
actor.fieldNo := fieldNum;
actor.ascending := not sortKey.fDescending;
actor.random := false;
actors.add(actor);
fieldNum := fieldNum + 1;
keyStart := keyStart + actor.length;
endforeach;
oidPosition := keyStart;
i := app.clock;
// now, write the objects to the source file
foreach obj in self do
line := "";
foreach sortKey in sortKeys do
propValue := obj.getPropertyValue(sortKey.fPropertyName);
propString := propValue.String[1:sortKey.fLength].padBlanks(sortKey.fLength);
line := line & propString;
endforeach;
oid := obj.getOidString;
line := line & oid;
sortSrc.writeLine(line);
endforeach;
sortSrc.close;
write "Write to file takes " & (app.clock - i).String;
// perform the sort
i := app.clock;
sortSrc.extractSort(actors, sortDest);
write "Actual sort takes " & (app.clock - i).String;
// clear the collection
clear;
i := app.clock;
// reload the collection from the sorted file
sortDest.mode := File.Mode_Input;
sortDest.open;
while not sortDest.endOfFile do
line := sortDest.readLine;
oid := line[oidPosition:end];
obj := oid.asOid;
add(obj);
endwhile;
write "Read from file takes: " & (app.clock - i).String;
epilog
sortSrc.purge;
sortDest.purge;
delete sortSrc;
delete sortDest;
actors.purge;
delete actors;
end;
Hello All
I've been doing some experiments on sorting an array at runtime. The basic requirement is to have an array of objects and sort the objects in the array according to one or more of their properties, kind of like specifiying the keys for a member key dictionary at runtime. This sort of thing is very useful where users want to specify the order of records in their reports etc.
Anyway, since JADE lacks such a feature I thought I'd have a go at implementing this using the extractSort method on the File class.
I added a method to the ObjectArray class to sort its contents. The method takes a collection of SortKey objects (of my own devising) which basically store the name of the property on the class, the length, whether or not the key is numeric and whether or not the key should be sorted ascending or descending.
The idea is that each object in the array gets its key values written to the file, along with its Oid so that it can be identified on the way back in. The file is sorted, then the collection cleared, then the collection is re-populated from the sorted file.
Thus, all the objects in the collection will magically appear sorted.
The reason for this post is that the performance (as you can imagine) isn't very good. Here's the details:
Sort of a collection with 1 key containing 2000 objects takes about 8 seconds - pretty bad. However, when the actual parts of the sorting are broken down, the file sort actually only takes about 1/2 a second (much more respectable). It's the writing and reading the file that takes the time.
So, what I would propose is that JADE have a feature that allows this sorting to happen WITHOUT having to write objects out to a file.
Here's the code, in case you want to try it yourself. There are various things you'd need to do to make it work in your environment (like creating the SortKey and SortKeyArray classes, and implementing a getTempFileName method on app).
sort(sortKeys: SortKeyArray) lockReceiver, updating;
vars
sortSrc,
sortDest : File;
srcFileName,
destFileName : String;
actor : SortActor;
actors : SortActorArray;
sortKey : SortKey;
pos,
fieldNum,
keyStart,
oidPosition : Integer;
obj : Object;
oid,
line : String;
propValue : Any;
propString : String;
i : Integer;
begin
create sortSrc transient;
srcFileName := app.getTempFileName("srt",0);
sortSrc.fileName := srcFileName;
sortSrc.recordSize := 0;
sortSrc.endOfLine := CrLf;
create sortDest transient;
destFileName := app.getTempFileName("srt",0);
sortDest.fileName := destFileName;
sortDest.allowReplace := true;
sortDest.allowCreate := true;
create actors transient;
actors.kway := 3;
// create the SortActor objects
keyStart := 1;
fieldNum := 1;
foreach sortKey in sortKeys do
create actor;
actor.numeric := sortKey.fNumeric;
actor.length := sortKey.fLength;
actor.startPosition := keyStart;
actor.fieldNo := fieldNum;
actor.ascending := not sortKey.fDescending;
actor.random := false;
actors.add(actor);
fieldNum := fieldNum + 1;
keyStart := keyStart + actor.length;
endforeach;
oidPosition := keyStart;
i := app.clock;
// now, write the objects to the source file
foreach obj in self do
line := "";
foreach sortKey in sortKeys do
propValue := obj.getPropertyValue(sortKey.fPropertyName);
propString := propValue.String[1:sortKey.fLength].padBlanks(sortKey.fLength);
line := line & propString;
endforeach;
oid := obj.getOidString;
line := line & oid;
sortSrc.writeLine(line);
endforeach;
sortSrc.close;
write "Write to file takes " & (app.clock - i).String;
// perform the sort
i := app.clock;
sortSrc.extractSort(actors, sortDest);
write "Actual sort takes " & (app.clock - i).String;
// clear the collection
clear;
i := app.clock;
// reload the collection from the sorted file
sortDest.mode := File.Mode_Input;
sortDest.open;
while not sortDest.endOfFile do
line := sortDest.readLine;
oid := line[oidPosition:end];
obj := oid.asOid;
add(obj);
endwhile;
write "Read from file takes: " & (app.clock - i).String;
epilog
sortSrc.purge;
sortDest.purge;
delete sortSrc;
delete sortDest;
actors.purge;
delete actors;
end;