diff --git a/changelog.md b/changelog.md index ba8985166d4ea..ebba903166cbc 100644 --- a/changelog.md +++ b/changelog.md @@ -85,6 +85,7 @@ slots when enlarging a sequence. objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc` instead of `--mm:orc`. - A `$` template is provided for `Path` in `std/paths`. +- `min`, `max`, and `sequtils`' `minIndex`, `maxIndex` and `minmax` for `openArray`s now accept a comparison function. - `std/hashes.hash(x:string)` changed to produce a 64-bit string `Hash` (based on Google's Farm Hash) which is also often faster than the present one. Define `nimStringHash2` to get the old values back. `--jsbigint=off` mode always only diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 3c0d8dc0ebee2..8d767b95c1f60 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -248,6 +248,21 @@ 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): bool): int {.effectsOf: cmp.} = + ## Returns the index of the minimum value of `s`. + ## `cmp` should return true if `a` is *less* than `b`. + runnableExamples: + import std/sugar + + let s1 = @["foo","bar", "hello"] + let s2 = @[2..4, 1..3, 6..10] + assert minIndex(s1, proc (a, b: string): bool = 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]): 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,6 +280,20 @@ 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): bool): int {.effectsOf: cmp.} = + ## Returns the index of the maximum value of `s`. + ## `cmp` should return true if `a` is *less* than `b`. + runnableExamples: + import std/sugar + + let s1 = @["foo","bar", "hello"] + let s2 = @[2..4, 1..3, 6..10] + assert maxIndex(s1, proc (a, b: string): bool = 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]): 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] @@ -274,6 +303,14 @@ func minmax*[T](x: openArray[T]): (T, T) = if h < x[i]: h = x[i] result = (l, h) +func minmax*[T](x: openArray[T], cmp: proc(a, b: T): bool): (T, T) {.effectsOf: cmp.} = + ## The minimum and maximum values of `x`. + ## `cmp` should return true if `a` is *less* than `b`. + result = (x[0], x[0]) + for i in 1..high(x): + if cmp(x[i], result[0]): result[0] = x[i] + if cmp(result[1], x[i]): result[1] = x[i] + template zipImpl(s1, s2, retType: untyped): untyped = proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index a8d78bb93a705..e4e511f5e61ba 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -265,12 +265,26 @@ proc min*[T](x: openArray[T]): T = for i in 1..high(x): if x[i] < result: result = x[i] +proc min*[T](x: openArray[T], cmp: proc(a, b: T): bool): T {.effectsOf: cmp.} = + ## The minimum value of `x`. + ## `cmp` should return true if `a` is *less* than `b`. + result = x[0] + for i in 1..high(x): + if cmp(x[i], result): result = x[i] + proc max*[T](x: openArray[T]): T = ## The maximum value of `x`. `T` needs to have a `<` operator. result = x[0] for i in 1..high(x): if result < x[i]: result = x[i] +proc max*[T](x: openArray[T], cmp: proc(a, b: T): bool): T {.effectsOf: cmp.} = + ## The maximum value of `x`. + ## `cmp` should return true if `a` is *less* than `b`. + result = x[0] + for i in 1..high(x): + if cmp(result, x[i]): result = x[i] + {.pop.} # stackTrace: off