1

I have a list of sets, ss, and want to test whether a 'test' meets the condition:

For each set in ss, there must be at one element in the set present in 'test'.

The code is below:

ss = [{"a"}, {"c", "d", "e"}, {"b", "g"}]

test1 = {'a', 'c', 'b'}
test2 = {'a', 'c'}

print('Test1: ')
def match(ss, test):
    for s in ss:
        overlap = not s.isdisjoint(test)
        if not overlap:
            return False

    return True

print(match(ss, test1)) // true
print(match(ss, test2))  // false

Any loophole, or is there a better way to do it?

2
  • I think your question would be better off on codereview.stackexchange.com, because it's a relatively open-ended question how to improve the code. For a question here, I'd at least expect you to define "better" when asking for such a way to do it. Commented Jul 16, 2021 at 21:20
  • @UlrichEckhardt I mainly mean 'faster' when doing this. Commented Jul 16, 2021 at 21:23

3 Answers 3

1

That looks fine to me, since looking at the code conveys its meaning well. What I would suggest is that you avoid the double not though:

disjoint = s.isdisjoint(test)
if disjoint:
    return False

This might make the logic a bit easier to follow. And once you have that, you can also get rid of that variable and just check the isdisjoint value directly:

if s.isdisjoint(test):
    return False

That’s where I would leave it at, to keep the logic easy to follow.

If you really wanted, you could shorten it to a single line though:

def match(ss, test):
    return all(not s.isdisjoint(test) for s in ss)

As for performance or correctness, you won’t be able to get better than this with these requirements: In order to tell whether any element of one set (test) is included in every set from a list of sets, you will have to check each of those sets. So that justifies your loop over those sets. And when you are looking for an intersection of two sets, then using the standard set operations will be as good as you can get.

If you had more specialized requirements, or some longer series of tests where you could make some assumptions from earlier test results (e.g. by ordering your test sets in some way or another), then there might be some further optimizations but if we’re just looking a single test using match, then I would think that you are already optimized enough that you shouldn’t need to worry about it.

Sign up to request clarification or add additional context in comments.

2 Comments

My choice of word 'overlap' is blocking me to make it simpler, although I tried to removing the double not.
I like this one better.
0

You can do a simple comprehension to determine the matching elements and then check wether the list of sets that fulfill the condition is the same as ss:

ss = [{"a"}, {"c", "d", "e"}, {"b", "g"}]

test1 = {'a', 'c', 'b'}
test2 = {'a', 'c'}

def match(ss, test):
    matching = [s for s in ss if any(i for i in s if i in test)]
    return matching == ss

match(ss, test1) -> True
match(ss, test2) -> False

Comments

0

Another option could be .intersection(another_set). For each set in the list, You're going to ask if test has at least one element in common. Using comprehension-list would be:

def match(ss, test):
   return all(len(test.intersection(s)) > 0 for s in ss)

Without comprehension-list:

def match(ss, test):
   answers = []
   for s in ss:
      answers.append(len(test.intersection(s)) > 0)
   return all(answers)

print(match(ss, test1)) # True
print(match(ss, test2)) # False

2 Comments

A good use case of issuperset(), which I am not aware of.
I had to change the issuperset() because I hadn't understood correctly the question :-|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.