Skip to content

Commit 24c468d

Browse files
authored
specialize argmin/argmax on ranges (#34315)
Also: document and add test_broken on argmin of degenerate ranges
1 parent be54a6c commit 24c468d

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

base/range.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,40 @@ maximum(r::AbstractUnitRange) = isempty(r) ? throw(ArgumentError("range must be
606606
minimum(r::AbstractRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : min(first(r), last(r))
607607
maximum(r::AbstractRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : max(first(r), last(r))
608608

609+
"""
610+
argmin(r::AbstractRange)
611+
612+
Ranges can have multiple minimal elements. In that case
613+
`argmin` will return a minimal index, but not necessarily the
614+
first one.
615+
"""
616+
function argmin(r::AbstractRange)
617+
if isempty(r)
618+
throw(ArgumentError("range must be non-empty"))
619+
elseif step(r) > 0
620+
firstindex(r)
621+
else
622+
first(searchsorted(r, last(r)))
623+
end
624+
end
625+
626+
"""
627+
argmax(r::AbstractRange)
628+
629+
Ranges can have multiple maximal elements. In that case
630+
`argmax` will return a maximal index, but not necessarily the
631+
first one.
632+
"""
633+
function argmax(r::AbstractRange)
634+
if isempty(r)
635+
throw(ArgumentError("range must be non-empty"))
636+
elseif step(r) > 0
637+
first(searchsorted(r, last(r)))
638+
else
639+
firstindex(r)
640+
end
641+
end
642+
609643
extrema(r::AbstractRange) = (minimum(r), maximum(r))
610644

611645
# Ranges are immutable

test/ranges.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,31 @@ end
12121212
@test convert(Array{Float64,1}, r) == a
12131213
end
12141214

1215+
@testset "extrema" begin
1216+
@test_throws ArgumentError minimum(1:2:-1)
1217+
@test_throws ArgumentError argmin(Base.OneTo(-1))
1218+
@test_throws ArgumentError maximum(Base.OneTo(-1))
1219+
@test_throws ArgumentError argmax(1:-1)
1220+
1221+
for (r, imin, imax) in [
1222+
(Base.OneTo(5), 1, 5),
1223+
(1:10, 1, 10),
1224+
(10:-1:0, 11, 1),
1225+
(range(10, stop=20, length=5), 1, 5),
1226+
(range(10.3, step=-2, length=7), 7, 1),
1227+
]
1228+
@test minimum(r) === r[imin]
1229+
@test maximum(r) === r[imax]
1230+
@test imin === argmin(r)
1231+
@test imax === argmax(r)
1232+
@test extrema(r) === (r[imin], r[imax])
1233+
end
1234+
1235+
r = 1f8-10:1f8
1236+
@test_broken argmin(f) == argmin(collect(r))
1237+
@test_broken argmax(f) == argmax(collect(r))
1238+
end
1239+
12151240
@testset "OneTo" begin
12161241
let r = Base.OneTo(-5)
12171242
@test isempty(r)
@@ -1227,6 +1252,8 @@ end
12271252
@test last(r) == 3
12281253
@test minimum(r) == 1
12291254
@test maximum(r) == 3
1255+
@test argmin(r) == 1
1256+
@test argmax(r) == 3
12301257
@test r[2] == 2
12311258
@test r[2:3] === 2:3
12321259
@test_throws BoundsError r[4]

test/sorting.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ end
189189
@test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll)
190190
end
191191
end
192+
@testset "issue ##34408" begin
193+
r = 1f8-10:1f8
194+
# collect(r) = Float32[9.999999e7, 9.999999e7, 9.999999e7, 9.999999e7, 1.0e8, 1.0e8, 1.0e8, 1.0e8, 1.0e8]
195+
@test_broken searchsorted(collect(r)) == searchsorted(r)
196+
end
192197
end
193198
@testset "issue #35272" begin
194199
for v0 = (3:-1:1, 3.0:-1.0:1.0), v = (v0, collect(v0))

0 commit comments

Comments
 (0)