Skip to content

Commit f6d1032

Browse files
authored
Add insorted for in function in sorted arrays (#37490)
1 parent 6596f95 commit f6d1032

File tree

6 files changed

+94
-1
lines changed

6 files changed

+94
-1
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ New library functions
7676
* New function `sincospi` for simultaneously computing `sinpi(x)` and `cospi(x)` more
7777
efficiently ([#35816]).
7878
* New function `addenv` for adding environment mappings into a `Cmd` object, returning the new `Cmd` object.
79+
* New function `insorted` for determining whether an element is in a sorted collection or not ([#37490]).
7980

8081
New library features
8182
--------------------

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ export
458458
searchsorted,
459459
searchsortedfirst,
460460
searchsortedlast,
461+
insorted,
461462
startswith,
462463

463464
# linear algebra

base/operators.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,8 @@ splat(f) = args->f(args...)
10951095
in(x)
10961096
10971097
Create a function that checks whether its argument is [`in`](@ref) `x`, i.e.
1098-
a function equivalent to `y -> y in x`.
1098+
a function equivalent to `y -> y in x`. See also [`insorted`](@ref) for the use
1099+
with sorted collections.
10991100
11001101
The returned function is of type `Base.Fix2{typeof(in)}`, which can be
11011102
used to implement specialized methods.

base/sort.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export # also exported by Base
2727
searchsorted,
2828
searchsortedfirst,
2929
searchsortedlast,
30+
insorted,
3031
# order & algorithm:
3132
sort,
3233
sort!,
@@ -407,6 +408,39 @@ julia> searchsortedlast([1, 2, 4, 5, 5, 7], 0) # no match, insert at start
407408
```
408409
""" searchsortedlast
409410

411+
"""
412+
insorted(a, x; by=<transform>, lt=<comparison>, rev=false)
413+
414+
Determine whether an item is in the given sorted collection, in the sense that
415+
it is [`==`](@ref) to one of the values of the collection according to the order
416+
specified by the `by`, `lt` and `rev` keywords, assuming that `a` is already
417+
sorted in that order, see [`sort`](@ref) for the keywords. See also
418+
[`in`](@ref). Returns a `Bool` value.
419+
420+
# Examples
421+
```jldoctest
422+
julia> insorted(4, [1, 2, 4, 5, 5, 7]) # single match
423+
true
424+
425+
julia> insorted(5, [1, 2, 4, 5, 5, 7]) # multiple matches
426+
true
427+
428+
julia> insorted(3, [1, 2, 4, 5, 5, 7]) # no match
429+
false
430+
431+
julia> insorted(9, [1, 2, 4, 5, 5, 7]) # no match
432+
false
433+
434+
julia> insorted(0, [1, 2, 4, 5, 5, 7]) # no match
435+
false
436+
```
437+
438+
!!! compat "Julia 1.6"
439+
`insorted` was added in Julia 1.6.
440+
"""
441+
function insorted end
442+
insorted(x, v::AbstractVector; kw...) = !isempty(searchsorted(v, x; kw...))
443+
insorted(x, r::AbstractRange) = in(x, r)
410444

411445
## sorting algorithms ##
412446

doc/src/base/sort.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ Base.issorted
125125
Base.Sort.searchsorted
126126
Base.Sort.searchsortedfirst
127127
Base.Sort.searchsortedlast
128+
Base.Sort.insorted
128129
Base.Sort.partialsort!
129130
Base.Sort.partialsort
130131
Base.Sort.partialsortperm

test/sorting.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,61 @@ Base.step(r::ConstantRange) = 0
299299
end
300300
end
301301
end
302+
@testset "insorted" begin
303+
numTypes = [Int8, Int16, Int32, Int64, Int128,
304+
UInt8, UInt16, UInt32, UInt64, UInt128,
305+
Float16, Float32, Float64, BigInt, BigFloat]
306+
307+
@test insorted(1, collect(1:10), by=(>=(5)))
308+
@test insorted(10, collect(1:10), by=(>=(5)))
309+
310+
for R in numTypes, T in numTypes
311+
@test !insorted(T(0), R[1, 1, 2, 2, 3, 3])
312+
@test insorted(T(1), R[1, 1, 2, 2, 3, 3])
313+
@test insorted(T(2), R[1, 1, 2, 2, 3, 3])
314+
@test !insorted(T(4), R[1, 1, 2, 2, 3, 3])
315+
@test !insorted(2.5, R[1, 1, 2, 2, 3, 3])
316+
317+
@test !insorted(T(0), 1:3)
318+
@test insorted(T(1), 1:3)
319+
@test insorted(T(2), 1:3)
320+
@test !insorted(T(4), 1:3)
321+
322+
@test insorted(T(1), R.(collect(1:10)), by=(>=(5)))
323+
@test insorted(T(10), R.(collect(1:10)), by=(>=(5)))
324+
end
325+
326+
for (rg,I) in [(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)]
327+
rg_r = reverse(rg)
328+
rgv, rgv_r = collect(rg), collect(rg_r)
329+
for i = I
330+
@test insorted(i,rg) === insorted(i,rgv)
331+
@test insorted(i,rg_r) === insorted(i,rgv_r,rev=true)
332+
end
333+
end
334+
335+
rg = 0.0:0.01:1.0
336+
for i = 2:101
337+
@test insorted(rg[i], rg)
338+
@test !insorted(prevfloat(rg[i]), rg)
339+
@test !insorted(nextfloat(rg[i]), rg)
340+
end
341+
342+
rg_r = reverse(rg)
343+
for i = 1:100
344+
@test insorted(rg_r[i], rg_r)
345+
@test !insorted(prevfloat(rg_r[i]), rg_r)
346+
@test !insorted(nextfloat(rg_r[i]), rg_r)
347+
end
348+
349+
@test insorted(1, 1:10) == insorted(1, collect(1:10), by=(>=(5)))
350+
@test insorted(10, 1:10) == insorted(10, collect(1:10), by=(>=(5)))
351+
352+
@test !insorted(0, [])
353+
@test !insorted(0, [1,2,3])
354+
@test !insorted(4, [1,2,3])
355+
@test insorted(3, [10,8,6,9,4,7,2,5,3,1], by=(x -> iseven(x) ? x+5 : x), rev=true)
356+
end
302357
@testset "PartialQuickSort" begin
303358
a = rand(1:10000, 1000)
304359
# test PartialQuickSort only does a partial sort

0 commit comments

Comments
 (0)