###########################################################################
#
# File: sort.icn
#
# Subject: Procedures for sorting
#
# Authors: Bob Alexander, Richard L. Goerwitz, and Ralph E. Griswold
#
# Date: September 10, 1998
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# isort(x, p)
# customized sort in which procedure p is used for
# comparison.
#
# sortff(L, fields[])
# like sortf(), except takes an unlimited number of field
# arguments.
#
# sortgen(T, m)
# generates sorted output in a manner specified by m:
#
# "k+" sort by key in ascending order
# "k-" sort by key in descending order
# "v+" sort by value in ascending order
# "v-" sort by value in descending order
#
# sortt(T, i)
# like sort(T, i) but produces a list of two-element records
# instead of a list of two-element lists.
#
############################################################################
#
# Customizable sort procedure for inclusion in Icon programs.
#
# isort(x,keyproc,y)
#
# Argument x can be any Icon data type that is divisible into elements
# by the unary element generation (!) operator. The result is a list
# of the objects in sorted order.
#
# The default is to sort elements in their natural, Icon-defined order.
# However, an optional parameter (keyproc) allows a sort key to be
# derived from each element, rather than the default of using the
# element itself as the key. Keyproc can be a procedure provided by
# the caller, in which case the first argument to the key procedure is
# the item for which the key is to be computed, and the second argument
# is isort's argument y, passed unchanged. The keyproc must produce
# the extracted key. Alternatively, the keyproc argument can be an
# integer, in which case it specifies a subscript to be applied to each
# item to produce a key. Keyproc will be called once for each element
# of structure x.
#
############################################################################
procedure isort(x,keyproc,y)
local items,item,key,result
if y := integer(keyproc) then
keyproc := proc("[]",2)
else /keyproc := 1
items := table()
every item := !x do {
key := keyproc(item,y)
(/items[key] := [item]) | put(items[key],item)
}
items := sort(items,3)
result := []
while get(items) do every put(result,!get(items))
return result
end
#
# 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 fields[1],
# and, for those elements having an identical fields[1], sub-
# sorted on field[2], etc.
#
procedure sortff(L, fields[]) #: sort on multiple 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
procedure sortgen(T, m) #: generate by different sorting orders
local L
L := sort(T, case m of {
"k+" | "k-": 1
"v+" | "v-": 2
})
case m of {
"k+" | "v+": suspend !L
"k-" | "v-": suspend L[*L to 1 by -1]
}
end
record element(key, value)
procedure sortt(T, i) #: sort to produce list of records
local result, k
if not(integer(i) = (1 | 2)) then runerr(205, i)
result := []
every put(result, element(k := key(T), T[k]))
return sortf(result, i)
end
This page produced by UniDoc on 2021/04/15 @ 23:59:44.