Merge pull request #4304 from kawaii-Code/linear_search_reverse

Add linear_search_reverse and linear_search_reverse_proc
This commit is contained in:
Laytan
2024-09-29 21:18:49 +02:00
committed by GitHub
2 changed files with 160 additions and 24 deletions

View File

@@ -96,9 +96,37 @@ contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comp
return found
}
/*
Searches the given slice for the given element in O(n) time.
If you need a custom search condition, see `linear_search_proc`
Inputs:
- array: The slice to search in.
- key: The element to search for.
Returns:
- index: The index `i`, such that `array[i]` is the first occurrence of `key` in `array`, or -1 if `key` is not present in `array`.
Example:
index: int
found: bool
a := []i32{10, 10, 10, 20}
index, found = linear_search_reverse(a, 10)
assert(index == 0 && found == true)
index, found = linear_search_reverse(a, 30)
assert(index == -1 && found == false)
// Note that `index == 1`, since it is relative to `a[2:]`
index, found = linear_search_reverse(a[2:], 20)
assert(index == 1 && found == true)
*/
@(require_results)
linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
where intrinsics.type_is_comparable(T) #no_bounds_check {
where intrinsics.type_is_comparable(T) {
for x, i in array {
if x == key {
return i, true
@@ -107,8 +135,18 @@ linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
return -1, false
}
/*
Searches the given slice for the first element satisfying predicate `f` in O(n) time.
Inputs:
- array: The slice to search in.
- f: The search condition.
Returns:
- index: The index `i`, such that `array[i]` is the first `x` in `array` for which `f(x) == true`, or -1 if such `x` does not exist.
*/
@(require_results)
linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check {
linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) {
for x, i in array {
if f(x) {
return i, true
@@ -118,22 +156,88 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
}
/*
Binary search searches the given slice for the given element.
If the slice is not sorted, the returned index is unspecified and meaningless.
Searches the given slice for the given element in O(n) time, starting from the
slice end.
If the value is found then the returned int is the index of the matching element.
If there are multiple matches, then any one of the matches could be returned.
If you need a custom search condition, see `linear_search_reverse_proc`
If the value is not found then the returned int is the index where a matching
element could be inserted while maintaining sorted order.
Inputs:
- array: The slice to search in.
- key: The element to search for.
# Examples
Returns:
- index: The index `i`, such that `array[i]` is the last occurrence of `key` in `array`, or -1 if `key` is not present in `array`.
Example:
index: int
found: bool
a := []i32{10, 10, 10, 20}
index, found = linear_search_reverse(a, 20)
assert(index == 3 && found == true)
index, found = linear_search_reverse(a, 10)
assert(index == 2 && found == true)
index, found = linear_search_reverse(a, 30)
assert(index == -1 && found == false)
// Note that `index == 1`, since it is relative to `a[2:]`
index, found = linear_search_reverse(a[2:], 20)
assert(index == 1 && found == true)
*/
@(require_results)
linear_search_reverse :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
where intrinsics.type_is_comparable(T) {
#reverse for x, i in array {
if x == key {
return i, true
}
}
return -1, false
}
/*
Searches the given slice for the last element satisfying predicate `f` in O(n)
time, starting from the slice end.
Inputs:
- array: The slice to search in.
- f: The search condition.
Returns:
- index: The index `i`, such that `array[i]` is the last `x` in `array` for which `f(x) == true`, or -1 if such `x` does not exist.
*/
@(require_results)
linear_search_reverse_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) {
#reverse for x, i in array {
if f(x) {
return i, true
}
}
return -1, false
}
/*
Searches the given slice for the given element.
If the slice is not sorted, the returned index is unspecified and meaningless.
If the value is found then the returned int is the index of the matching element.
If there are multiple matches, then any one of the matches could be returned.
If the value is not found then the returned int is the index where a matching
element could be inserted while maintaining sorted order.
For slices of more complex types see: `binary_search_by`
Example:
/*
Looks up a series of four elements. The first is found, with a
uniquely determined position; the second and third are not
found; the fourth could match any position in `[1, 4]`.
*/
```
index: int
found: bool
@@ -150,9 +254,6 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
index, found = slice.binary_search(s, 1)
assert(index >= 1 && index <= 4 && found == true)
```
For slices of more complex types see: binary_search_by
*/
@(require_results)
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
@@ -161,21 +262,21 @@ binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
}
/*
Binary search searches the given slice for the given element.
If the slice is not sorted, the returned index is unspecified and meaningless.
Searches the given slice for the given element.
If the slice is not sorted, the returned index is unspecified and meaningless.
If the value is found then the returned int is the index of the matching element.
If there are multiple matches, then any one of the matches could be returned.
If the value is found then the returned int is the index of the matching element.
If there are multiple matches, then any one of the matches could be returned.
If the value is not found then the returned int is the index where a matching
element could be inserted while maintaining sorted order.
If the value is not found then the returned int is the index where a matching
element could be inserted while maintaining sorted order.
The array elements and key may be different types. This allows the filter procedure
to compare keys against a slice of structs, one struct value at a time.
The array elements and key may be different types. This allows the filter procedure
to compare keys against a slice of structs, one struct value at a time.
Returns:
index: int
found: bool
Returns:
- index: int
- found: bool
*/
@(require_results)

View File

@@ -306,3 +306,38 @@ test_compare_empty :: proc(t: ^testing.T) {
testing.expectf(t, slice.equal(c[:], d[:]),
"Expected two separate empty slices of two dynamic arrays to be equal")
}
@test
test_linear_search_reverse :: proc(t: ^testing.T) {
index: int
found: bool
s := []i32{0, 50, 50, 100}
index, found = slice.linear_search_reverse(s, 100)
testing.expect(t, found)
testing.expect_value(t, index, len(s) - 1)
index, found = slice.linear_search_reverse(s[len(s) - 1:], 100)
testing.expect(t, found)
testing.expect_value(t, index, 0)
index, found = slice.linear_search_reverse(s, 50)
testing.expect(t, found)
testing.expect_value(t, index, 2)
index, found = slice.linear_search_reverse(s, 0)
testing.expect(t, found)
testing.expect_value(t, index, 0)
index, found = slice.linear_search_reverse(s, -1)
testing.expect(t, !found)
less_than_80 :: proc(x: i32) -> bool {
return x < 80
}
index, found = slice.linear_search_reverse_proc(s, less_than_80)
testing.expect(t, found)
testing.expect_value(t, index, 2)
}