; docformat = 'rst' ;+ ; An alternative to IDL's SORT function that employs a ; `radix-sort algorithm `. This ; algorithm is stable but slower than the ; `quicksort algorithm ` used in IDL's ; `SORT` function. ; ; :History: ; Derived from code by Atle Borsholm, VIS, 2012 ;- ;+ ; Handle special case of sorting string arrays. ; ; Note that this is very slow compared to `SORT` in most cases. However, it is ; a stable sort. ; ; :Returns: ; `lonarr(n_elements(data))` ; ; :Params: ; data : in, required, type=strarr ; array of strings to sort ;- function mg_sort_strings, data compile_opt idl2, logical_predicate len = strlen(data) maxlen = max(len) sorted = data radix = 256 ; fixed to byte for each character indices = lindgen(n_elements(data)) for i = maxlen - 1L, 0L, -1L do begin ; use a nice feature of IDL: byte('') = [0b] digit = byte(strmid(sorted, i, 1L)) h = histogram(digit, reverse_indices=ri) sorted = sorted[ri[radix + 1L:*]] indices = indices[ri[radix + 1L:*]] endfor return, indices end ;+ ; Radix sort input data. ; ; :Returns: ; `lonarr(n_elements(data))` ; ; :Params: ; data : in, required, type="int, long, float, double, or string array" ; data to sort ; ; :Keywords: ; radix : in, optional, type=int, default=256 ; radix to use for sort ;- function mg_sort, data, radix=radix compile_opt idl2, logical_predicate ; default radix if not specified _radix = n_elements(radix) eq 0L ? 256 : radix ; support signed ints case size(data, /type) of 2: sorted = uint(data) + ishft(1us, 15) ; +/- are equivalent here 3: sorted = ulong(data) + ishft(1ul, 31) 4: begin sorted = ulong(data, 0, n_elements(data)) sorted xor= ((sorted and ishft(1ul, 31)) ne 0) * (not ishft(1ul, 31)) sorted += ishft(1ul, 31) end 5: begin sorted = ulong64(data, 0, n_elements(data)) ; IEEE does not use 2's complement for negative numbers so, flip the ; bits for the negative numbers with this trick this may not be 100% ; IEEE compliant sorting, but works well for finite numbers at least sorted xor= ((sorted and ishft(1ull, 63)) ne 0) * (not ishft(1ull, 63)) sorted += ishft(1ull, 63) end 7: return, mg_sort_strings(data) 14: sorted = ulong64(data) + ishft(1ull, 63) else: sorted = data endcase indices = lindgen(n_elements(data)) mx = max(sorted, min=mn) ; implement a slight speed improvement for small data ranges rng = mx - mn if (rng lt mn / _radix) then begin sorted -= mn mx -= mn endif factor = 1ull while (mx gt 0) do begin mx /= _radix rem = sorted / factor digit = rem mod _radix factor = factor * _radix h = histogram(digit, min=0, max=_radix-1, binsize=1, reverse_indices=ri) ind = ri[_radix + 1:*] sorted = sorted[ind] indices = indices[ind] endwhile return, indices end