{ DC> I'm setting up a directory list with some extra bells and whistles, DC> including descriptions. I want to be able to have different sort criteria DC> for the list, and the list should be in a DC> TSortedCollection. DC> 1. The most simple-minded. instantiate four different lists, and use just DC> one, DC> 2. Alternate procedures for each type of sort, calling common routines, or DC> passing the current collection type. DC> 3. A variant record to save the collection in. DC> The Question: Would this idea work, and do you think it's the best way to DC> do it? I have one program with the same problem, and I can suggest two more ways to do what you want: 4. A field in the collection saying which kind of sort you want, and a Resort method. The KeyOf and/or Compare methods look at this field to decide how two records compare, and the Resort method re-inserts everything after you change the field, so it ends up in the correct order. 5. A non-method SortCollection function, that takes a Compare function as a procedural parameter. You can use a TCollection if you're not interested in the search functions, or some variation on 4 if you are. I don't know which you'll find best. Depends on your taste. Here's some code that I use; you may want to borrow from it. {$N-,Q-} unit sorts; interface uses objects,base3; { base3 can also be found in the SWAG collection !! } type comparison = function(a,b:pointer):boolean; { Returns true if a^ > b^ } local_comparison = function(a,b:pointer;frame:word):boolean; { A far local version of a comparison } procedure list_sort(var start:pointer; greater:comparison); { Procedure to do list insertion sort on the linked list pointed to by start. Greater points to the entry for a far function with declaration function greater^(i,j:pointer):boolean which returns true if i^ > j^ and false otherwise. Assumes that pointers point to pointers, i.e. links should be the first element of records in the list. N.B. If enough memory is available, it seems to be faster to make the list into an array, use arr_sort, and then un_make the array when there are more than about 100 records. } procedure arr_sort(var arr;size:word;greater:comparison); { Procedure to do a Quicksort on the array of pointers pointed to by arr. Greater is as in list_sort. Makes no assumptions about what pointers point to. Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom 1986. } procedure SortCollection(var Coll:TCollection;GreaterP:pointer); { Sorts a collection's pointers. Greater should be a pointer to a local_comparison } function count_list(list:pointer):longint; { Counts the number of elements in the list} function make_array(list:pointer;size:longint;var arr:pointer):boolean; { Attempts to make an array of pointers from the list. Returns true on success, false if it failed because not enough memory is available. Always creates an array with size elements, but only fills those up to the smaller of the actual size of the list or size. } procedure un_make_array(var list:pointer;size:integer;var arr); { Adjusts the pointers in the list to reflect the ordering in the array. Doesn't check that they are all valid - be sure size reflects the true number of pointers in the array. } type PSortableCollection = ^TSortableCollection; TSortableCollection = object(TSortedCollection) procedure Sort; { Puts the elements of the collection in order. This is only necessary if something about the sort order has changed, or elements were inserted out of order. } end; implementation type list_ptr = ^list_rec; list_rec = record next : list_ptr; end; ptr_array = array[1..16380] of pointer; procedure list_sort(var start:pointer; greater:comparison); var first,rest,current,next:list_ptr; begin rest := list_ptr(start)^.next; { Rest points to the uninserted part of the list } first := start; { first is a fake first entry in the new list } first^.next := nil; start := @first; while rest <> nil do begin current := start; next := current^.next; while (next <> nil) and (not greater(next,rest)) do begin current := next; next := current^.next; end; current^.next := rest; current := rest; rest := rest^.next; current^.next := next; end; start := first; end; procedure arr_sort(var arr;size:word;greater:comparison); { Procedure to do a Quicksort on the array of pointers pointed to by arr. Greater is as in list_sort. Makes no assumptions about what pointers point to. Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom 1986. } var a:ptr_array absolute arr; procedure quick(first,last : word); var pivot : pointer; temp : pointer; scanright, scanleft : word; begin if (first < last) then begin pivot := a[first]; scanright := first; scanleft := last; while scanright < scanleft do begin if greater(a[scanright+1], pivot) then begin if not greater(a[scanleft], pivot) then begin temp := a[scanleft]; inc(scanright); a[scanleft] := a[scanright]; a[scanright] := temp; dec(scanleft); end else dec(scanleft); end else inc(scanright); end; temp := a[scanright]; a[scanright] := a[first]; a[first] := temp; quick(first, scanright-1); quick(scanright+1, last); end; end; begin {arr_sort} quick(1, size); end; function count_list(list:pointer):longint; { Counts the number of elements in a list } var l:list_ptr absolute list; size:longint; begin size := 0; while l <> nil do begin inc(size); l := l^.next; end; count_list := size; end; function make_array(list:pointer;size:longint;var arr:pointer):boolean; { Attempts to make an array of pointers from the list. Returns true on success, false if it failed because not enough memory is available } var l:list_ptr absolute list; mem_needed:longint; a:^ptr_array absolute arr; i:integer; begin mem_needed := size*sizeof(pointer); if (mem_needed > 65520) or (mem_needed > MemAvail) then begin make_array := false; exit; end; GetMem(a,mem_needed); i := 0; while (i nil) do begin inc(i); a^[i] := l; l := l^.next; end; make_array := true; end; procedure un_make_array(var list:pointer;size:integer;var arr); { Adjusts the pointers in the list to reflect the ordering in the array. Doesn't check that they are all valid - be sure size reflects the true number of pointers in the array. } var l:list_ptr absolute list; current,next:list_ptr; a:ptr_array absolute arr; i:integer; begin l := a[1]; current := l; for i := 2 to size do begin next := a[i]; current^.next := next; current := next; end; current^.next := nil; end; procedure TSortableCollection.Sort; { Procedure to do a Quicksort on the collection elements. Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom 1986. } procedure quick(first,last : word); var pivot : pointer; temp : pointer; scanright, scanleft, tielimit : word; direction : integer; begin if (first+1) < (last+1) then { This allows for last=-1 } begin { First, choose a random pivot } scanright := first+random(last-first); pivot := items^[scanright]; items^[scanright] := items^[first]; items^[first] := pivot; scanright := first; scanleft := last; tielimit := (first+last) div 2; while scanright < scanleft do begin direction := compare(items^[scanright+1], pivot); if (direction>0) or ((direction = 0) and (scanright > tielimit)) then begin if compare(items^[scanleft], pivot)<=0 then begin temp := items^[scanleft]; inc(scanright); items^[scanleft] := items^[scanright]; items^[scanright] := temp; dec(scanleft); end else dec(scanleft); end else inc(scanright); end; temp := items^[scanright]; items^[scanright] := items^[first]; items^[first] := temp; quick(first, scanright-1); quick(scanright+1, last); end; end; begin {sort} quick(0, pred(count)); end; procedure SortCollection(var Coll:TCollection;GreaterP:pointer); { Procedure to do a Quicksort on the collection elements. Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom 1986. } var Greater : local_comparison absolute GreaterP; Frame : word; procedure quick(first,last : word); var pivot : pointer; temp : pointer; scanright, scanleft : word; begin with Coll do begin if (first+1) < (last+1) then { This allows for last=-1 } begin pivot := items^[first]; scanright := first; scanleft := last; while scanright < scanleft do begin if greater(items^[scanright+1], pivot, Frame) then begin if not greater(items^[scanleft], pivot, Frame) then begin temp := items^[scanleft]; inc(scanright); items^[scanleft] := items^[scanright]; items^[scanright] := temp; dec(scanleft); end else dec(scanleft); end else inc(scanright); end; temp := items^[scanright]; items^[scanright] := items^[first]; items^[first] := temp; quick(first, scanright-1); quick(scanright+1, last); end; end; end; begin {sort} frame := CallerFrame; quick(0, pred(coll.count)); end; end.