39
39
!! TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
40
40
!! SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41
41
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
53
43
use stdlib_kinds, only: &
54
44
int8, &
55
45
int16, &
@@ -60,74 +50,62 @@ module stdlib_sorting_unique
60
50
xdp, &
61
51
qp, &
62
52
lk
63
-
64
- use stdlib_sorting, only: sort
65
-
66
53
use stdlib_optval, only: optval
67
-
68
54
use stdlib_string_type, only: string_type, assignment(=), operator(==)
69
-
70
55
implicit none
71
- private
72
56
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
115
58
116
59
#: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)
118
61
!! Version: experimental
119
62
!!
120
63
!! `${name1}$_unique(array, sorted)` returns an array of unique values
121
64
!! 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(:)
128
70
129
- end interface unique
71
+ ${t2}$ :: temp_array(size(array))
72
+ logical :: mask(size(array))
73
+ integer :: i, n
74
+ logical :: is_input_sorted
130
75
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
132
110
133
- end module stdlib_sorting_unique
111
+ end submodule stdlib_sorting_unique
0 commit comments