The Python Oracle

Python set intersection question

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Ocean Floor

--

Chapters
00:00 Python Set Intersection Question
00:22 Accepted Answer Score 2
01:24 Answer 2 Score 14
01:30 Answer 3 Score 2
02:00 Answer 4 Score 5
02:13 Thank you

--

Full question
https://stackoverflow.com/questions/3837...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #set

#avk47



ANSWER 1

Score 14


all(any(a & b for a in s if a is not b) for b in s)



ANSWER 2

Score 5


Here's a very simple solution that's very efficient for large inputs:

def g(s):
    import collections
    count = collections.defaultdict(int)
    for a in s:
        for x in a:
            count[x] += 1
    return all(any(count[x] > 1 for x in a) for a in s)



ACCEPTED ANSWER

Score 2


It's a little verbose but I think it's a pretty efficient solution. It takes advantage of the fact that when two sets intersect, we can mark them both as connected. It does this by keeping a list of flags as long as the list of sets. when set i and set j intersect, it sets the flag for both of them. It then loops over the list of sets and only tries to find a intersection for sets that haven't already been intersected. After reading the comments, I think this is what @Victor was talking about.

s0 = [set([16,9,2,10]), set([16,14,22,15]), set([14,7])]   # true, 16 and 14
s1 = [set([16,9,2,10]), set([16,14,22,15]), set([7,8])]    # false


def connected(sets):
    L = len(sets)

    if not L: return True
    if L == 1: return False

    passed = [False] * L
    i = 0
    while True:
        while passed[i]: 
            i += 1
            if i == L: 
                return True

        for j, s in enumerate(sets):
            if j == i: continue
            if sets[i] & s: 
                passed[i] = passed[j] = True
                break
        else:
            return False


print connected(s0)
print connected(s1)

I decided that an empty list of sets is connected (If you produce an element of the list, I can produce an element that it intersects ;). A list with only one element is dis-connected trivially. It's one line to change in either case if you disagree.




ANSWER 4

Score 2


Here's a more efficient (if much more complicated) solution, that performs a linear number of intersections and a number of unions of order O( n*log(n) ), where n is the length of s:

def f(s):
    import math
    j = int(math.log(len(s) - 1, 2)) + 1
    unions = [set()] * (j + 1)
    for i, a in enumerate(s):
        unions[:j] = [set.union(set(), *s[i+2**k:i+2**(k+1)]) for k in range(j)]
        if not (a & set.union(*unions)):
            return False
        j = int(math.log(i ^ (i + 1), 2))
        unions[j] = set.union(a, *unions[:j])
    return True

Note that this solution only works on Python >= 2.6.