############################################################################ # # Name: sortff.icn # # Title: sortf with multiple field arguments # # Author: Bob Alexander and Richard L. Goerwitz # # Date: July 14, 1993 # ############################################################################ # # Sortff is like sortf(), except takes an unlimited number of field # arguments. E.g. if you want to sort a list of structures on field # 5, and (for those objects that have the same field 5) do a sub-sort # on field 2, you would use "sortff(list_of_objects, 5, 2)." # ############################################################################ # # sortff: structure [x integer [x integer...]] -> structure # (L, [fields ...]) -> new_L # # Where L is any subscriptable structure, and fields are any # number of integer subscripts in any desired order. Returns # a copy of structure L with its elements sorted on field 1, # and, for those elements having an identical field 1, sub- # sorted on field 2, etc. # procedure sortff(L, fields[]) *L <= 1 & { return copy(L) } return sortff_1(L, fields, 1, []) end procedure sortff_1(L, fields, k, uniqueObject) local sortField, cachedKeyValue, i, startOfRun, thisKey sortField := fields[k] L := sortf(L, sortField) # initial sort using fields[k] # # If more than one sort field is given, use each field successively # as the current key, and, where members in L have the same value for # this key, do a subsort using fields[k+1]. # if fields[k +:= 1] then { # # Set the equal-key-run pointer to the start of the list and # save the value of the first key in the run. # startOfRun := 1 cachedKeyValue := L[startOfRun][sortField] | uniqueObject every i := 2 to *L do { thisKey := L[i][sortField] | uniqueObject if not (thisKey === cachedKeyValue) then { # # We have an element with a sort key different from the # previous. If there's a run of more than one equal keys, # sort the sublist. # if i - startOfRun > 1 then { L := L[1:startOfRun] ||| sortff_1(L[startOfRun:i], fields, k, uniqueObject) ||| L[i:0] } # Reset the equal-key-run pointer to this key and cache. startOfRun := i cachedKeyValue := L[startOfRun][sortField] | uniqueObject } } # # Sort a final run if it exists. # if i - startOfRun > 1 then { L := L[1:startOfRun] ||| sortff_1(L[startOfRun:0], fields, k, uniqueObject) } } return L end