3939!! TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
4040!! SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4141
42- module stdlib_sorting_unique
43- !! This module implements overloaded unique functions that can be used to extract
44- !! unique values from arrays of various types: integer, real, complex, character,
45- !! and string_type.
46- !! ([Specification](../page/specs/stdlib_sorting_unique.html))
47- !!
48- !! By default, the output array is not sorted, but this can be changed
49- !! with the optional parameter `sorted`. When sorted, the output will
50- !! be in order of increasing value. All functions have worst case
51- !! run time performance of `O(N Ln(N))` due to the sorting step.
52-
42+ submodule (stdlib_sorting) stdlib_sorting_unique
5343 use stdlib_kinds, only: &
5444 int8, &
5545 int16, &
@@ -60,74 +50,62 @@ module stdlib_sorting_unique
6050 xdp, &
6151 qp, &
6252 lk
63-
64- use stdlib_sorting, only: sort
65-
6653 use stdlib_optval, only: optval
67-
6854 use stdlib_string_type, only: string_type, assignment(=), operator(==)
69-
7055 implicit none
71- private
7256
73- public :: unique
74-
75- interface unique
76- !! Version: experimental
77- !!
78- !! The generic function implementing the `unique` algorithm to return
79- !! a new array containing only the unique values from the input array.
80- !! Its use has the syntax:
81- !!
82- !! result = unique(array[, sorted])
83- !!
84- !! with the arguments:
85- !!
86- !! * array: the rank 1 array from which to extract unique values. It is an `intent(in)`
87- !! argument of any of the types `integer(int8)`, `integer(int16)`,
88- !! `integer(int32)`, `integer(int64)`, `real(real32)`, `real(real64)`,
89- !! `real(real128)`, `complex(real32)`, `complex(real64)`, `complex(real128)`,
90- !! `character(*)`, or `type(string_type)`.
91- !!
92- !! * sorted (optional): shall be a scalar of type default logical. It
93- !! is an `intent(in)` argument. If present with a value of `.true.` then
94- !! the returned array will be sorted in order of non-decreasing values.
95- !! Otherwise the order is unspecified, but generally reflects the order of
96- !! first appearance of each unique value in the input array.
97- !!
98- !!#### Example
99- !!
100- !!```fortran
101- !! ...
102- !! ! Extract unique values from an array
103- !! integer :: x(5) = [1, 2, 3, 3, 4]
104- !! integer, allocatable :: y(:)
105- !!
106- !! y = unique(x) ! y will be [1, 2, 3, 4]
107- !!
108- !! ! Use with optional sorted argument
109- !! real :: a(8) = [3.1, 2.5, 7.2, 3.1, 2.5, 8.0, 7.2, 9.5]
110- !! real, allocatable :: b(:)
111- !!
112- !! b = unique(a, sorted=.true.) ! b will be [2.5, 3.1, 7.2, 8.0, 9.5]
113- !! ...
114- !!```
57+ contains
11558
11659#:for t1, t2, name1 in IRSC_TYPES_ALT_NAME
117- pure module function ${name1}$_unique(array, sorted) result(unique_values)
60+ pure module procedure ${name1}$_unique(array, sorted) result(unique_values)
11861!! Version: experimental
11962!!
12063!! `${name1}$_unique(array, sorted)` returns an array of unique values
12164!! from the input `array` of type `${t1}$`. If the optional argument `sorted`
122- !! is present with value `.true.`, the returned array will be sorted.
123- ${t1}$, intent(in) :: array(:)
124- logical(lk), intent(in), optional :: sorted
125- ${t2}$, allocatable :: unique_values(:)
126- end function ${name1}$_unique
127- #:endfor
65+ !! is present with value `.true.`, the function assumes the input is already sorted
66+ !! and skips the sorting step.
67+ ${t1}$, intent(in) :: array(:)
68+ logical(lk), intent(in), optional :: sorted
69+ ${t2}$, allocatable :: unique_values(:)
12870
129- end interface unique
71+ ${t2}$ :: temp_array(size(array))
72+ logical :: mask(size(array))
73+ integer :: i, n
74+ logical :: is_input_sorted
13075
131- contains
76+ n = size(array)
77+
78+ ! Handle edge cases first
79+ if (n == 0) then
80+ ! Return empty array for empty input
81+ allocate(unique_values(0))
82+ return
83+ else if (n == 1) then
84+ ! For single-element arrays, return that element directly
85+ allocate(unique_values(1))
86+ unique_values(1) = array(1)
87+ return
88+ endif
89+
90+ ! Determine if the input is already sorted
91+ is_input_sorted = optval(sorted, .false.)
92+
93+ ! Create a temporary copy and sort it if needed
94+ temp_array = array
95+ if (.not. is_input_sorted) call sort(temp_array)
96+
97+ ! Find unique elements using a mask
98+ ! Start with first element always marked as unique
99+ mask(1) = .true.
100+
101+ ! Compare each element with previous to mark duplicates
102+ do concurrent (i=2:n)
103+ mask(i) = temp_array(i) /= temp_array(i-1)
104+ end do
105+
106+ ! Extract unique elements to result array using pack
107+ unique_values = pack(temp_array, mask)
108+ end procedure ${name1}$_unique
109+ #:endfor
132110
133- end module stdlib_sorting_unique
111+ end submodule stdlib_sorting_unique
0 commit comments