PRO unique_elements, data, unique, nunique, UNIQUE_SUBS = unique_subs, REPEAT_SUBS = repeat_subs, NREPEAT = nrepeat, ORIGINAL_ORDERING = original_ordering, $
; Description: This module determines the set of unique elements in the input array "data" and returns
; this set as a vector of unique elements "unique" sorted into ascending order, along with
; the number of unique elements "nunique". There are also options to return the subscripts
; of the unique elements in the input array "data" via the keyword UNIQUE_SUBS, the
; subscripts of the repeat elements in the input array "data" via the keyword REPEAT_SUBS,
; and the number of repeat elements in the input array "data" via the keyword NREPEAT.
; The module also provides the option of returning the set of unique elements in the input
; array "data" in the same order as the original ordering of the elements in "data", rather
; than returning the set of unique elements sorted into ascending order. In this case, the
; subscripts "unique_subs" and "repeat_subs" of the unique and repeat elements,
; respectively, in the input array "data" will also be in the order corresponding to the
; original ordering of the elements in "data" (which happens to be in ascending order for
; the subscripts themselves!). This behaviour may be achieved by setting the keyword
; ORIGINAL_ORDERING.
;
; Input Parameters:
;
; data - ANY SCALAR/VECTOR/ARRAY - A scalar/vector/array of input data. This parameter must be defined,
; and not a structure.
;
; Output Parameters:
;
; unique - VECTOR (same type as "data") - A one-dimensional vector consisting of the set of unique
; elements in "data" sorted into ascending order. If the
; keyword ORIGINAL_ORDERING is set (see below), then the
; ordering of the elements in "unique" matches the original
; ordering of the elements in "data".
; nunique - LONG - The number of elements in the output parameter "unique". This parameter is set to
; "0" if "data" is undefined or a structure.
;
; Keywords:
;
; If the keyword UNIQUE_SUBS is set to a named variable, then, on return, this variable will contain
; a vector of LONG type numbers representing the subscripts of the unique elements in the input array
; "data". In this case "unique" and "data[unique_subs]" are the same vectors.
;
; If the keyword REPEAT_SUBS is set to a named variable, then, on return, this variable will contain
; a vector of LONG type numbers representing the subscripts of the repeat elements in the input array
; "data". The repeat elements themselves may be obtained by constructing the vector "data[repeat_subs]".
; Note that if there are no repeat elements in the input array "data", then "repeat_subs" is set to
; the single element vector "[-1L]".
;
; If the keyword NREPEAT is set to a named variable, then, on return, this variable will contain a
; number of LONG type that represents the number of repeat elements in the input array "data".
;
; If the keyword ORIGINAL_ORDERING is set (as "/ORIGINAL_ORDERING), then the unique elements "unique"
; will be returned in the same order as the original ordering of the elements in "data", rather than
; being returned in ascending order. Furthermore, the subscripts "unique_subs" and "repeat_subs" of
; the unique and repeat elements, respectively, will be in the order corresponding to the original
; ordering of the elements in "data" (which happens to be in ascending order for the subscripts
; themselves!).
;
; If the keyword DATA_ALREADY_SORTED is set (as "/DATA_ALREADY_SORTED"), then the module will assume
; that the values of "data" are already sorted into ascending order. This option can be used to avoid
; a number of operations including a sort operation on the input parameter "data", which allows the
; user to build more efficient code with this module.
;
; Author: Dan Bramich (dan.bramich@hotmail.co.uk)
;
; History:
;
; 02/03/2011 - Added the keywords REPEAT_SUBS, NREPEAT and ORIGINAL_ORDERING (dmb).
; 02/05/2010 - Module created (dmb).
;Set the default output parameter values
;Check that "data" is defined, and that it is not a structure
;Determine the number of elements in "data"
;If "data" has one element
;If "data" is already sorted
;Find the positions in the data where adjacent elements are different
;If all the elements in "data" are unique
;Construct the output vector of unique elements, and the subscripts of the unique and repeat
;elements in "data", and then finish
;If only one element in "data" is unique
;Construct the output vector of unique elements, and the subscripts of the unique and repeat
;elements in "data", and then finish
;Otherwise, determine the subscripts of the unique and repeat elements in "data"
;Construct the output vector of unique elements, and then finish
;If "data" is not already sorted, then sort "data"
;Find the positions in the sorted data vector where adjacent elements are different
;If all the elements in "data" are unique
;If the keyword ORIGINAL_ORDERING is set
;Construct the output vector of unique elements, and the subscripts of the unique and repeat
;elements in "data", such that the ordering matches the original ordering of the elements in
;"data", and then finish
;If the keyword ORIGINAL_ORDERING is not set
;Construct the output vector of unique elements, and the subscripts of the unique and repeat
;elements in "data", such that the unique elements are arranged in ascending order, and then
;finish
;If only one element in "data" is unique
;Construct the output vector of unique elements, and the subscripts of the unique and repeat
;elements in "data", and then finish
;Otherwise, determine the subscripts of the unique and repeat elements in "data" such that the
;unique elements are arranged in ascending order
;If the keyword ORIGINAL_ORDERING is set
;Reorder the subscripts of the unique and repeat elements in "data" such that the ordering
;matches the original ordering of the elements in "data"
;Construct the output vector of unique elements in the required order