astroturfdurf
astroturfdurf

Reputation: 37

Python sets: "in" set command not working

I have a list of tuples that I want to get all the combinations for as a set and filter out certain sets based on criteria.

For example

pairs = [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
combs = []
for i in range(len(pairs)):
        intermediate = (set(list(combinations(pairs, i))))
        if ((2,3) and (2,2) and (3,2)) in intermediate:
                combs.append(intermediate)

But it doesn't detect if any of the tuples are in the set, so I tried a more basic test version.

pairs = [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
test = set(combinations(pairs,1))
if (1,1) in test:
        print("true")

This also doesn't work even though I can clearly see in my variable explorer that the set contains (1,1).

I've also tried adding an integer 1 as one of the elements in pairs and checking if 1 is in the set but that still doesn't work. I've run out of ideas and some help would be appreciated.

Upvotes: 0

Views: 889

Answers (2)

Aaron
Aaron

Reputation: 11075

There are two issues here...

First, it would seem like you are not testing membership at the correct depth of a nested data structure. When you call set(combinations(pairs, i)), you get a structure that is 3 levels deep: A set of tuples of tuples of ints (ints 3 containers deep).

>>> pairs = [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
>>> test = set(combinations(pairs,1))
>>> test
{((3, 2),), ((2, 3),), ((1, 1),), ((2, 2),), ((3, 1),), ((1, 3),), ((1, 2),), ((3, 3),), ((2, 1),)}

It is perfectly valid to test if a specific tuple of tuples of ints is contained within the set, but those tuples aren't automatically flattened for you to be able to test against a simple tuple of ints.

>>> ((1,1),) in test
True
>>> (1,1) in test
False

If you want to check if any tuples within the set contain a specific sub-tuple, you'll have to iterate over the set and check each top level tuple individually (hint: things like map can make this iteration a little shorter and sweeter)

for top_tuple in test:
    if (1,1) in top_tuple:
        print("found it!")

Second, is a somewhat common trap for new python programmers, which is chaining logical operators. You must think of and or in etc.. as similar to mathematical operators similar to + - * / etc.. The other important thing is how the logical operators treat things that aren't True and False. In general python treats things that are empty such as empty lists, strings, tuples, sets, etc.. as False, as well as things that are equal to 0. Basically everything else non-zero or non-empty is treated as True. Then when you run into an and, if the first value (on the left) is True-ish the return value of the and statement will be whatever is on the right. if The first value is False-ish, the return value will be that first value. When you chain them together, they get evaluated left to right.

>>> (1,1) and "cookies"
"cookies"
>>> False and "cookies"
False
>>> (2,3) and (2,2) and (3,2)
(3, 2)

Upvotes: 1

pakpe
pakpe

Reputation: 5489

Here is your test set, which does not contain (1,1) as an isolated tuple. It is a tuple inside a tuple.

{((3, 2),), ((2, 3),), ((1, 1),), ((2, 2),), ((3, 1),), ((1, 3),), ((1, 2),), ((3, 3),), ((2, 1),)}

To detect it, you can:

for combo in test:
    if (1,1) in combo:
        print("true")

#output: true

Upvotes: 1

Related Questions