-
Notifications
You must be signed in to change notification settings - Fork 185
Implement a unique function returning only the unique values in a vector. #940 #965
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
adc27a4
02ecfc6
53eaa12
10d7bd4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,176 @@ | ||||||||||||||||||||||||||||||||||
--- | ||||||||||||||||||||||||||||||||||
title: unique function | ||||||||||||||||||||||||||||||||||
--- | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# The `unique` function | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
[TOC] | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Introduction | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
This function returns an array containing only the unique values extracted from an input array. This is useful for removing duplicates from datasets and finding the distinct elements in a collection. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Status | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
The `unique` function is currently in **experimental** status. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Version History | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same format as the other |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|Version|Change| | ||||||||||||||||||||||||||||||||||
|---|---| | ||||||||||||||||||||||||||||||||||
|v0.1.0|Initial functionality in experimental status| | ||||||||||||||||||||||||||||||||||
Comment on lines
+19
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Requirements | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
This function has been designed to handle arrays of different types, including intrinsic numeric types, character arrays, and `string_type` arrays. The function should be efficient while maintaining an easy-to-use interface. | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are not requirements. The content of these sentences will be included in the description of the API of |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Usage | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
```fortran | ||||||||||||||||||||||||||||||||||
! Get unique values from an integer array | ||||||||||||||||||||||||||||||||||
integer :: x(5) = [1, 2, 3, 3, 4] | ||||||||||||||||||||||||||||||||||
integer, allocatable :: y(:) | ||||||||||||||||||||||||||||||||||
y = unique(x) ! y will be [1, 2, 3, 4] | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
! Get sorted unique values from a real array | ||||||||||||||||||||||||||||||||||
real :: a(8) = [3.1, 2.5, 7.2, 3.1, 2.5, 8.0, 7.2, 9.5] | ||||||||||||||||||||||||||||||||||
real, allocatable :: b(:) | ||||||||||||||||||||||||||||||||||
b = unique(a, sorted=.true.) ! b will be [2.5, 3.1, 7.2, 8.0, 9.5] | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To me, having the syntax
would imply that on entry |
||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## API | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
### `unique` - Returns unique values from an array | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#### Interface | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
```fortran | ||||||||||||||||||||||||||||||||||
pure function unique(array, sorted) result(unique_values) | ||||||||||||||||||||||||||||||||||
<type>, intent(in) :: array(:) | ||||||||||||||||||||||||||||||||||
logical, intent(in), optional :: sorted | ||||||||||||||||||||||||||||||||||
<type>, allocatable :: unique_values(:) | ||||||||||||||||||||||||||||||||||
end function unique | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
Comment on lines
+47
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unique_values = stdlib_sorting(module):unique(procedure) ( array[, sorted]) |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
where `<type>` can be any of: | ||||||||||||||||||||||||||||||||||
* `integer(int8)`, `integer(int16)`, `integer(int32)`, `integer(int64)` | ||||||||||||||||||||||||||||||||||
* `real(sp)`, `real(dp)`, `real(xdp)`, `real(qp)` | ||||||||||||||||||||||||||||||||||
* `complex(sp)`, `complex(dp)`, `complex(xdp)`, `complex(qp)` | ||||||||||||||||||||||||||||||||||
* `character(len=*)` | ||||||||||||||||||||||||||||||||||
* `type(string_type)` | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#### Arguments | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
`array`: Array whose unique values need to be extracted. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
`sorted` (optional): Whether the output vector needs to be sorted or not. Default is `.false.`. | ||||||||||||||||||||||||||||||||||
Comment on lines
+55
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#### Result | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
The function returns an allocatable array containing only the unique values from the input array. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
If `sorted` is `.true.`, the returned array will be sorted in order of non-decreasing values. | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest to use |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
If `sorted` is `.false.` (the default), the order of elements is unspecified but generally reflects the order of first appearance of each unique value in the input array. | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Examples | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
### Example 1: Basic usage with integers | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Examples should be in separate files. Keeping them in separate files allows them to be compiled and tested. |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
```fortran | ||||||||||||||||||||||||||||||||||
program example_unique_integers | ||||||||||||||||||||||||||||||||||
use stdlib_sorting, only: unique | ||||||||||||||||||||||||||||||||||
implicit none | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
integer :: data(10) = [1, 2, 3, 3, 4, 5, 5, 6, 6, 6] | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could it be a parameter? |
||||||||||||||||||||||||||||||||||
integer, allocatable :: unique_values(:) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
! Get unique values | ||||||||||||||||||||||||||||||||||
unique_values = unique(data) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
! Print the results | ||||||||||||||||||||||||||||||||||
print *, "Original array: ", data | ||||||||||||||||||||||||||||||||||
print *, "Unique values: ", unique_values | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
end program example_unique_integers | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
Expected output: | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
Original array: 1 2 3 3 4 5 5 6 6 6 | ||||||||||||||||||||||||||||||||||
Unique values: 1 2 3 4 5 6 | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
Comment on lines
+98
to
+102
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Include this in the code itself. |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
### Example 2: Using the sorted option with real values | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
```fortran | ||||||||||||||||||||||||||||||||||
program example_unique_reals | ||||||||||||||||||||||||||||||||||
use stdlib_kinds, only: sp | ||||||||||||||||||||||||||||||||||
use stdlib_sorting, only: unique | ||||||||||||||||||||||||||||||||||
implicit none | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
real(sp) :: data(8) = [3.1, 2.5, 7.2, 3.1, 2.5, 8.0, 7.2, 9.5] | ||||||||||||||||||||||||||||||||||
real(sp), allocatable :: unique_values(:) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
! Get unique values in sorted order | ||||||||||||||||||||||||||||||||||
unique_values = unique(data, sorted=.true.) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
! Print the results | ||||||||||||||||||||||||||||||||||
print *, "Original array: ", data | ||||||||||||||||||||||||||||||||||
print *, "Sorted unique values: ", unique_values | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
end program example_unique_reals | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
Expected output: | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
Original array: 3.1 2.5 7.2 3.1 2.5 8.0 7.2 9.5 | ||||||||||||||||||||||||||||||||||
Sorted unique values: 2.5 3.1 7.2 8.0 9.5 | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
### Example 3: Working with character arrays | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
```fortran | ||||||||||||||||||||||||||||||||||
program example_unique_strings | ||||||||||||||||||||||||||||||||||
use stdlib_sorting, only: unique | ||||||||||||||||||||||||||||||||||
implicit none | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
character(len=6) :: data(7) = ["apple ", "banana", "cherry", "apple ", "date ", "banana", "cherry"] | ||||||||||||||||||||||||||||||||||
character(len=6), allocatable :: unique_values(:) | ||||||||||||||||||||||||||||||||||
integer :: i | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
! Get unique values | ||||||||||||||||||||||||||||||||||
unique_values = unique(data) | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
! Print the results | ||||||||||||||||||||||||||||||||||
print *, "Original array:" | ||||||||||||||||||||||||||||||||||
do i = 1, size(data) | ||||||||||||||||||||||||||||||||||
print *, data(i) | ||||||||||||||||||||||||||||||||||
end do | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
print *, "Unique values:" | ||||||||||||||||||||||||||||||||||
do i = 1, size(unique_values) | ||||||||||||||||||||||||||||||||||
print *, unique_values(i) | ||||||||||||||||||||||||||||||||||
end do | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
end program example_unique_strings | ||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Implementation Notes | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
The implementation uses a sorting-based approach to identify unique elements efficiently. When `sorted=.true.`, the algorithm sorts the input array and then identifies adjacent duplicate elements. When `sorted=.false.`, the function still uses sorting internally but ensures that the order of first appearance is preserved. | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Future Enhancements | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
Future versions might include additional features: | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
1. Return the indices of the first occurrence of each unique element | ||||||||||||||||||||||||||||||||||
2. Return indices that can reconstruct the original array from the unique elements | ||||||||||||||||||||||||||||||||||
3. Support for multi-dimensional arrays | ||||||||||||||||||||||||||||||||||
4. Tolerance parameter for floating-point comparisons | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
## Related Functions | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
* `sort` - Sorts an array in ascending or descending order | ||||||||||||||||||||||||||||||||||
* `sort_index` - Creates index array that would sort an array | ||||||||||||||||||||||||||||||||||
* `ord_sort` - Performs a stable sort on an array | ||||||||||||||||||||||||||||||||||
Comment on lines
+172
to
+176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ ADD_EXAMPLE(sort) | |
ADD_EXAMPLE(sort_index) | ||
ADD_EXAMPLE(radix_sort) | ||
ADD_EXAMPLE(sort_bitset) | ||
ADD_EXAMPLE(unique) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
program example_unique | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you split this program in smaller programs and include them in the specs, please? |
||
use stdlib_kinds, only: dp, sp | ||
use stdlib_sorting, only: unique | ||
use stdlib_string_type, only: string_type | ||
implicit none | ||
|
||
! Example with integer array | ||
integer :: int_array(10) = [1, 2, 3, 3, 4, 5, 5, 6, 6, 6] | ||
integer, allocatable :: int_unique(:) | ||
|
||
! Example with real array | ||
real(sp) :: real_array(8) = [3.1, 2.5, 7.2, 3.1, 2.5, 8.0, 7.2, 9.5] | ||
real(sp), allocatable :: real_unique(:) | ||
|
||
! Example with character array | ||
character(len=6) :: char_array(7) = ["apple ", "banana", "cherry", "apple ", "date ", "banana", "cherry"] | ||
character(len=6), allocatable :: char_unique(:) | ||
|
||
! Example with string_type array | ||
type(string_type) :: string_array(8), string_unique_sorted(4) | ||
type(string_type), allocatable :: string_unique(:) | ||
|
||
integer :: i | ||
|
||
! Setup string array | ||
string_array(1) = "apple" | ||
string_array(2) = "banana" | ||
string_array(3) = "cherry" | ||
string_array(4) = "apple" | ||
string_array(5) = "date" | ||
string_array(6) = "banana" | ||
string_array(7) = "cherry" | ||
string_array(8) = "apple" | ||
|
||
! Get unique integer values | ||
int_unique = unique(int_array) | ||
print *, "Unique integers:", int_unique | ||
|
||
! Get sorted unique integer values | ||
int_unique = unique(int_array, sorted=.true.) | ||
print *, "Sorted unique integers:", int_unique | ||
|
||
! Get unique real values | ||
real_unique = unique(real_array) | ||
print *, "Unique reals:", real_unique | ||
|
||
! Get sorted unique real values | ||
real_unique = unique(real_array, sorted=.true.) | ||
print *, "Sorted unique reals:", real_unique | ||
|
||
! Get unique character values | ||
char_unique = unique(char_array) | ||
print *, "Unique strings:" | ||
do i = 1, size(char_unique) | ||
print *, char_unique(i) | ||
end do | ||
|
||
! Get unique string_type values (sorted) | ||
string_unique = unique(string_array, sorted=.true.) | ||
print *, "Sorted unique string_type values:" | ||
do i = 1, size(string_unique) | ||
print *, string_unique(i) | ||
end do | ||
end program example_unique |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
unique
is included instdlib_sorting
, the specs ofunique
should be added instdlib_sorting
.