443,369 Members | 1,147 Online Need help? Post your question and get tips & solutions from a community of 443,369 IT Pros & Developers. It's quick & easy.

# comparing values in two sets

 P: n/a I'd like to compare the values in two different sets to test if any of the positions in either set share the same value (e.g., if the third element of each set is an 'a', then the test fails). I have this: def test_sets(original_set, trans_letters): for pair in zip(original_set, trans_letters): if pair == pair: return False return True zip() was the first thing I thought of, but I was wondering if there's some other way to do it, perhaps a builtin that actually does this kind of testing. Thanks. May 14 '06 #1
11 Replies

 P: n/a John> I'd like to compare the values in two different sets to test if John> any of the positions in either set share the same value (e.g., if John> the third element of each set is an 'a', then the test fails). Do you really mean "set" and not "list"? Note that they are unordered. These two sets are equal: set(['b', 'a', 'c']) set(['a', 'b', 'c']) Skip May 14 '06 #2

 P: n/a Note that you are comparing ordered sequences, like lists, tuples, strings, etc, and not sets. Something like this can be a little improvement of your code, it avoids building the zipped list, and scans the iterable unpacking it on the fly: from itertools import izip def test_sets(original_set, trans_letters): for elem1, elem2 in izip(original_set, trans_letters): if elem1 == elem2: return False return True Bye, bearophile May 14 '06 #3

 P: n/a So you probably have to change the function test_sets name, because it's not much useful on real sets. Can't you use the == or != operators on those sequences? Bye, bearophile May 14 '06 #4

 P: n/a John Salerno wrote: I'd like to compare the values in two different sets to test if any of the positions in either set share the same value (e.g., if the third element of each set is an 'a', then the test fails). I have this: def test_sets(original_set, trans_letters): for pair in zip(original_set, trans_letters): if pair == pair: return False return True zip() was the first thing I thought of, but I was wondering if there's some other way to do it, perhaps a builtin that actually does this kind of testing. There is no such concept as "position in [a] set". Sets in math[s]/logic are *NOT* ordered. The order in which Python retrieves elements when you do (for example) list(a_set) is a meaningless artefact of the implementation du jour, and is not to be relied on. s = set(['xyzzy', 'plugh', 'sesame']) t = set(['xyzzy', 'plugh', 'mellon']) s set(['sesame', 'plugh', 'xyzzy']) t set(['plugh', 'mellon', 'xyzzy']) zip(s, t) [('sesame', 'plugh'), ('plugh', 'mellon'), ('xyzzy', 'xyzzy')] You may need one or more of these: s & t set(['plugh', 'xyzzy']) s ^ t set(['sesame', 'mellon']) s | t set(['sesame', 'plugh', 'mellon', 'xyzzy']) (s | t) - t set(['sesame']) (s | t) - s set(['mellon']) If that doesn't meet your needs: back up a level and tell us what you are trying to achieve If True: read about sets in the Python docs HTH, John May 14 '06 #5

 P: n/a > I'd like to compare the values in two different sets to test if any of the positions in either set share the same value (e.g., if the third element of each set is an 'a', then the test fails). There's an inherant problem with this...sets by definition are unordered, much like dictionaries. To compare them my such means, you'd have to convert them to lists, sort the lists by some ordering, and then compare the results. Something like s1 = set([1,3,5,7,9]) s2 = set([1,2,3]) list1 = list(s1) list2 = list(s2) list1.sort() list2.sort() if [(x,y) for x,y in zip(list1,list2) if x == y]: print "There's an overlap" else: print "No matching elements" Just to evidence matters, on my version of python (2.3.5 on Debian), the following came back: set([1,3,5,7,9]) set([1,3,9,5,7]) That's not the original order, but the definition of a set isn't hurt/changed by any ordering. Thus, asking for the "position in a set" is an undefined operation. -tkc PS: for the above was done in 2.3.5 using this line: from sets import Set as set May 15 '06 #6

 P: n/a John Salerno writes: I'd like to compare the values in two different sets to test if any of the positions in either set share the same value (e.g., if the third element of each set is an 'a', then the test fails). I think by "sets" you mean "lists". Sets are unordered, as a few people have mentioned. I have this: def test_sets(original_set, trans_letters): for pair in zip(original_set, trans_letters): if pair == pair: return False return True That's fairly reasonable. You could use itertools.izip instead of zip, which makes a generator instead of building up a whole new list in memory. A more traditional imperative-style version would be something like: def test_sets(original_set, trans_letters): for i in xrange(len(original_set)): if original_set[i] == trans_letters[i]: return True return False You could even get cutesy and say something like (untested): from itertools import izip def test_sets(original_set, trans_letters): return not sum(a==b for a,b in izip(original_set, trans_letters)) but that can be slower since it always scans both lists in entirety, even if a matching pair of elements is found right away. I don't offhand see a builtin function or not-too-obscure one-liner that short-circuits, but maybe there is one. Note that all the above examples assume the two lists are the same length. Otherwise, some adjustment is needed. May 15 '06 #7

 P: n/a John Salerno wrote: I'd like to compare the values in two different sets Oops, I guess I was a little too loose in my use of the word 'set'. I'm using sets in my program, but by this point they actually become strings, so I'm really comparing strings. Thanks for pointing that out to me, and I'll look into izip as well. I was wondering if I could use an iterator for this somehow. :) May 15 '06 #8

 P: n/a Paul Rubin wrote: You could even get cutesy and say something like (untested): from*itertools*import*izip def*test_sets(original_set,*trans_letters): return*not*sum(a==b*for*a,b*in*izip(original_set,* trans_letters)) but that can be slower since it always scans both lists in entirety, even if a matching pair of elements is found right away. Here's a variant that does performs only the necessary tests: from itertools import izip True not in (a == b for a, b in izip(range(3), range(3))) False A "noisy" equality test to demonstrate short-circuiting behaviour: def print_eq(a, b): .... print "%r == %r --> %r" % (a, b, a == b) .... return a == b .... True not in (print_eq(a, b) for a, b in izip(range(3), range(3))) 0 == 0 --> True False True not in (print_eq(a, b) for a, b in izip(["x", 1, 2], range(3))) 'x' == 0 --> False 1 == 1 --> True False True not in (print_eq(a, b) for a, b in izip(["x", "x", "x"], range(3))) 'x' == 0 --> False 'x' == 1 --> False 'x' == 2 --> False True Peter May 15 '06 #9

 P: n/a Peter Otten <__*******@web.de> writes: Here's a variant that does performs only the necessary tests: from itertools import izip True not in (a == b for a, b in izip(range(3), range(3))) Cute! May 15 '06 #10

 P: n/a John Salerno wrote: I'd like to compare the values in two different sets to test if any of the positions in either set share the same value (e.g., if the third element of each set is an 'a', then the test fails). I have this: def test_sets(original_set, trans_letters): for pair in zip(original_set, trans_letters): if pair == pair: return False return True zip() was the first thing I thought of, but I was wondering if there's some other way to do it, perhaps a builtin that actually does this kind of testing. Thanks. 'enumerate' is another possibility: s1 = 'abcd' s2 = 'zzzz' s3 = 'zbzz' s4 = 'zzbz' def are_itemwise_different( L1, L2 ): #if len(L1) != len(L2): return True for idx, value in enumerate(L1): if value == L2[idx]: return False return True #after Peter Otten def are_itemwise_different( L1, L2 ): #if len(L1) != len(L2): return True return True not in ( value == L2[idx] for idx, value in enumerate(L1) ) assert are_itemwise_different(s1,s2) assert not are_itemwise_different(s1,s3) assert are_itemwise_different(s1,s4) def itemwise_intersect( L1, L2 ): #if len(L1) != len(L2): raise for idx, value in enumerate(L1): if value == L2[idx]: yield value assert list(itemwise_intersect(s1,s2)) == [] assert list(itemwise_intersect(s1,s3)) == ['b'] assert list(itemwise_intersect(s1,s4)) == [] Gerard May 15 '06 #11

 P: n/a Gerard Flanagan wrote: John Salerno wrote: I'd like to compare the values in two different sets to test if any of the positions in either set share the same value (e.g., if the third element of each set is an 'a', then the test fails). I have this: def test_sets(original_set, trans_letters): for pair in zip(original_set, trans_letters): if pair == pair: return False return True zip() was the first thing I thought of, but I was wondering if there's some other way to do it, perhaps a builtin that actually does this kind of testing. Thanks. 'enumerate' is another possibility: s1 = 'abcd' s2 = 'zzzz' s3 = 'zbzz' s4 = 'zzbz' def are_itemwise_different( L1, L2 ): #if len(L1) != len(L2): return True for idx, value in enumerate(L1): if value == L2[idx]: return False return True #after Peter Otten def are_itemwise_different( L1, L2 ): return True not in ( val == L2[idx] for idx, val in enumerate(L1) ) assert are_itemwise_different(s1,s2) assert not are_itemwise_different(s1,s3) assert are_itemwise_different(s1,s4) s1 = 'abcd' s2 = 'zzzz' s3 = 'zbzz' s4 = 'zzbz' s5 = 'xbxx' def itemwise_intersect( L1, L2 ): return [value for idx, value in set(enumerate(L1)) & set(enumerate(L2))] assert itemwise_intersect(s1,s2) == [] assert itemwise_intersect(s1,s3) == ['b'] assert itemwise_intersect(s1,s4) == [] def itemwise_intersect( *args ): s = set(enumerate(args)) for t in ( set(enumerate(X)) for X in args[1:]): s.intersection_update(t) return [val for i,val in s] assert itemwise_intersect(s1,s3,s5) == ['b'] Gerard May 15 '06 #12

### This discussion thread is closed

Replies have been disabled for this discussion. 