Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isdisjoint #34427

Merged
merged 1 commit into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion base/abstractset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ true
"""
issubset, ⊆, ⊇

const FASTIN_SET_THRESHOLD = 70

function issubset(l, r)
if haslength(r) && (isa(l, AbstractSet) || !hasfastin(r))
rlen = length(r) # conditions above make this length computed only when needed
Expand All @@ -269,7 +271,7 @@ function issubset(l, r)
end
# when `in` would be too slow and r is big enough, convert it to a Set
# this threshold was empirically determined (cf. #26198)
if !hasfastin(r) && rlen > 70
if !hasfastin(r) && rlen > FASTIN_SET_THRESHOLD
return issubset(l, Set(r))
end
end
Expand Down Expand Up @@ -375,6 +377,30 @@ function issetequal(l, r)
return issetequal(Set(l), Set(r))
end

## set disjoint comparison
"""
isdisjoint(v1, v2) -> Bool

Returns whether the collections `v1` and `v2` are disjoint, i.e. whether
their intersection is empty.

!!! compat "Julia 1.5"
This function requires at least Julia 1.5.
"""
function isdisjoint(l, r)
function _isdisjoint(l, r)
hasfastin(r) && return !any(in(r), l)
hasfastin(l) && return !any(in(l), r)
haslength(r) && length(r) < FASTIN_SET_THRESHOLD &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note, in issubset the conversion to Set can be done only if haslength(r), here you made the opposite choice... Was it for a specific reason? (I didn't think much about it, but indeed converting to Set when length is unknown seems like a better choice to me; what about updating issubset then?).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, converting to Set in general seemed like a good idea to me, with the exception of a fast path when the thing we're iterating over happens to be short.

return !any(in(r), l)
return !any(in(Set(r)), l)
end
if haslength(l) && haslength(r) && length(r) < length(l)
return _isdisjoint(r, l)
end
_isdisjoint(l, r)
end

## partial ordering of sets by containment

==(l::AbstractSet, r::AbstractSet) = length(l) == length(r) && l ⊆ r
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ export
in,
intersect!,
intersect,
isdisjoint,
isempty,
issubset,
issetequal,
Expand Down
6 changes: 5 additions & 1 deletion test/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,15 @@ end
@test !(Set([1,2,3]) <= Set([1,2,4]))
end

@testset "issubset, symdiff" begin
@testset "issubset, symdiff, isdisjoint" begin
for S in (Set, BitSet, Vector)
for (l,r) in ((S([1,2]), S([3,4])),
(S([5,6,7,8]), S([7,8,9])),
(S([1,2]), S([3,4])),
(S([5,6,7,8]), S([7,8,9])),
(S([1,2,3]), S()),
(S(), S()),
(S(), S([1,2,3])),
(S([1,2,3]), S([1])),
(S([1,2,3]), S([1,2])),
(S([1,2,3]), S([1,2,3])),
Expand All @@ -317,6 +319,8 @@ end
@test issubset(intersect(l,r), r)
@test issubset(l, union(l,r))
@test issubset(r, union(l,r))
@test isdisjoint(l,l) == isempty(l)
@test isdisjoint(l,r) == isempty(intersect(l,r))
if S === Vector
@test sort(union(intersect(l,r),symdiff(l,r))) == sort(union(l,r))
else
Expand Down