Add min/max overloads with comparison functions (#23595)

`min`, `max`, `minmax`, `minIndex` and `maxIndex`
This commit is contained in:
Amjad Ben Hedhili
2025-05-06 13:09:03 +01:00
committed by GitHub
parent b50ab7a5c9
commit 59ceff4f1a
2 changed files with 48 additions and 2 deletions

View File

@@ -34,7 +34,7 @@ errors.
[//]: # "Changes:"
- `std/math` The `^` symbol now supports floating-point as exponent in addition to the Natural type.
- `min`, `max`, and `sequtils`' `minIndex`, `maxIndex` and `minmax` for `openArray`s now accept a comparison function.
- `system.substr` implementation now uses `copymem` (wrapped C `memcpy`) for copying data, if available at compilation.
- `system.newStringUninit` is now considered free of side-effects allowing it to be used with `--experimental:strictFuncs`.

View File

@@ -231,6 +231,18 @@ func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] =
for itm in items(s):
if not result.contains(itm): result.add(itm)
proc min*[T](x: openArray[T], cmp: proc(a, b: T): int): T {.effectsOf: cmp.} =
## The minimum value of `x`.
result = x[0]
for i in 1..high(x):
if cmp(x[i], result) < 0: result = x[i]
proc max*[T](x: openArray[T], cmp: proc(a, b: T): int): T {.effectsOf: cmp.} =
## The maximum value of `x`.
result = x[0]
for i in 1..high(x):
if cmp(result, x[i]) < 0: result = x[i]
func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
## Returns the index of the minimum value of `s`.
## `T` needs to have a `<` operator.
@@ -248,6 +260,20 @@ func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
for i in 1..high(s):
if s[i] < s[result]: result = i
func minIndex*[T](s: openArray[T], cmp: proc(a, b: T): int): int {.effectsOf: cmp.} =
## Returns the index of the minimum value of `s`.
runnableExamples:
import std/sugar
let s1 = @["foo","bar", "hello"]
let s2 = @[2..4, 1..3, 6..10]
assert minIndex(s1, proc (a, b: string): int = a.len - b.len) == 0
assert minIndex(s2, (a, b) => a.a - b.a) == 1
for i in 1..high(s):
if cmp(s[i], s[result]) < 0: result = i
func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
## Returns the index of the maximum value of `s`.
## `T` needs to have a `<` operator.
@@ -265,15 +291,35 @@ func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
for i in 1..high(s):
if s[i] > s[result]: result = i
func maxIndex*[T](s: openArray[T], cmp: proc(a, b: T): int): int {.effectsOf: cmp.} =
## Returns the index of the maximum value of `s`.
runnableExamples:
import std/sugar
let s1 = @["foo","bar", "hello"]
let s2 = @[2..4, 1..3, 6..10]
assert maxIndex(s1, proc (a, b: string): int = a.len - b.len) == 2
assert maxIndex(s2, (a, b) => a.a - b.a) == 2
for i in 1..high(s):
if cmp(s[result], s[i]) < 0: result = i
func minmax*[T](x: openArray[T]): (T, T) =
## The minimum and maximum values of `x`. `T` needs to have a `<` operator.
var l = x[0]
var h = x[0]
for i in 1..high(x):
if x[i] < l: l = x[i]
if h < x[i]: h = x[i]
elif h < x[i]: h = x[i]
result = (l, h)
func minmax*[T](x: openArray[T], cmp: proc(a, b: T): int): (T, T) {.effectsOf: cmp.} =
## The minimum and maximum values of `x`.
result = (x[0], x[0])
for i in 1..high(x):
if cmp(x[i], result[0]) < 0: result[0] = x[i]
elif cmp(result[1], x[i]) < 0: result[1] = x[i]
template zipImpl(s1, s2, retType: untyped): untyped =
proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType =