comparing values in two sets

Discussion in 'Python' started by John Salerno, May 14, 2006.

  1. John Salerno

    John Salerno Guest

    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[0] == pair[1]:
    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.
     
    John Salerno, May 14, 2006
    #1
    1. Advertising

  2. John Salerno

    Guest

    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 15, 2006
    #2
    1. Advertising

  3. John Salerno

    Guest

    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 15, 2006
    #3
  4. John Salerno

    Guest

    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 15, 2006
    #4
  5. John Salerno

    John Machin Guest

    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[0] == pair[1]:
    > 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/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
     
    John Machin, May 15, 2006
    #5
  6. John Salerno

    Tim Chase Guest

    > 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
     
    Tim Chase, May 15, 2006
    #6
  7. John Salerno

    Paul Rubin Guest

    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[0] == pair[1]:
    > 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 == trans_letters:
    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.
     
    Paul Rubin, May 15, 2006
    #7
  8. John Salerno

    John Salerno Guest

    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. :)
     
    John Salerno, May 15, 2006
    #8
  9. John Salerno

    Peter Otten Guest

    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
     
    Peter Otten, May 15, 2006
    #9
  10. John Salerno

    Paul Rubin Guest

    Peter Otten <> 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!
     
    Paul Rubin, May 15, 2006
    #10
  11. 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[0] == pair[1]:
    > 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
     
    Gerard Flanagan, May 15, 2006
    #11
  12. 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[0] == pair[1]:
    > > 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[0]))
    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
     
    Gerard Flanagan, May 15, 2006
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Doug

    Comparing node sets

    Doug, Jul 25, 2003, in forum: XML
    Replies:
    1
    Views:
    502
    Marrow
    Jul 25, 2003
  2. Andy Fish

    xpath: comparing two node sets

    Andy Fish, Mar 9, 2005, in forum: XML
    Replies:
    3
    Views:
    2,771
    Andy Fish
    Mar 10, 2005
  3. Replies:
    3
    Views:
    260
    Asun Friere
    Jul 10, 2007
  4. Terry L. Ridder
    Replies:
    4
    Views:
    129
    Quantum Mechanic
    Oct 14, 2003
  5. java
    Replies:
    7
    Views:
    276
Loading...

Share This Page