Skip to content

Commit

Permalink
optimize allunique() for sorted collections (#50372)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrstphrbrns authored Nov 22, 2023
1 parent abfc2c6 commit 418423b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
28 changes: 27 additions & 1 deletion base/set.jl
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ end
Return `true` if all values from `itr` are distinct when compared with [`isequal`](@ref).
`allunique` may use a specialized implementation when the input is sorted.
See also: [`unique`](@ref), [`issorted`](@ref), [`allequal`](@ref).
# Examples
Expand Down Expand Up @@ -494,7 +496,31 @@ allunique(::Union{AbstractSet,AbstractDict}) = true

allunique(r::AbstractRange) = !iszero(step(r)) || length(r) <= 1

allunique(A::StridedArray) = length(A) < 32 ? _indexed_allunique(A) : _hashed_allunique(A)
function allunique(A::StridedArray)
if length(A) < 32
_indexed_allunique(A)
elseif OrderStyle(eltype(A)) === Ordered()
a1, rest1 = Iterators.peel(A)
a2, rest = Iterators.peel(rest1)
if !isequal(a1, a2)
compare = isless(a1, a2) ? isless : (a,b) -> isless(b,a)
for a in rest
if compare(a2, a)
a2 = a
elseif isequal(a2, a)
return false
else
return _hashed_allunique(A)
end
end
else # isequal(a1, a2)
return false
end
return true
else
_hashed_allunique(A)
end
end

function _indexed_allunique(A)
length(A) < 2 && return true
Expand Down
3 changes: 3 additions & 0 deletions test/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,9 @@ end
@test !allunique([1,1,2])
@test !allunique([:a,:b,:c,:a])
@test allunique(unique(randn(100))) # longer than 32
@test allunique(collect(1:100)) # sorted/unique && longer than 32
@test allunique(collect(100:-1:1)) # sorted/unique && longer than 32
@test !allunique(fill(1,100)) # sorted/repeating && longer than 32
@test allunique(collect('A':'z')) # 58-element Vector{Char}
@test !allunique(repeat(1:99, 1, 2))
@test !allunique(vcat(pi, randn(1998), pi)) # longer than 1000
Expand Down

0 comments on commit 418423b

Please sign in to comment.