comparing values in two sets

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John Salerno

    #1

    comparing values in two sets

    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(origi nal_set, trans_letters):
    for pair in zip(original_se t, 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.
  • skip@pobox.com

    #2
    Re: comparing values in two sets


    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

    Comment

    • bearophileHUGS@lycos.com

      #3
      Re: comparing values in two sets

      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(origi nal_set, trans_letters):
      for elem1, elem2 in izip(original_s et, trans_letters):
      if elem1 == elem2:
      return False
      return True

      Bye,
      bearophile

      Comment

      • bearophileHUGS@lycos.com

        #4
        Re: comparing values in two sets

        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

        Comment

        • John Machin

          #5
          Re: comparing values in two sets

          John Salerno wrote:[color=blue]
          > 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(origi nal_set, trans_letters):
          > for pair in zip(original_se t, 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.[/color]

          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.
          [color=blue][color=green][color=darkred]
          >>> s = set(['xyzzy', 'plugh', 'sesame'])
          >>> t = set(['xyzzy', 'plugh', 'mellon'])
          >>> s[/color][/color][/color]
          set(['sesame', 'plugh', 'xyzzy'])[color=blue][color=green][color=darkred]
          >>> t[/color][/color][/color]
          set(['plugh', 'mellon', 'xyzzy'])[color=blue][color=green][color=darkred]
          >>> zip(s, t)[/color][/color][/color]
          [('sesame', 'plugh'), ('plugh', 'mellon'), ('xyzzy', 'xyzzy')][color=blue][color=green][color=darkred]
          >>>[/color][/color][/color]

          You may need one or more of these:[color=blue][color=green][color=darkred]
          >>> s & t[/color][/color][/color]
          set(['plugh', 'xyzzy'])[color=blue][color=green][color=darkred]
          >>> s ^ t[/color][/color][/color]
          set(['sesame', 'mellon'])[color=blue][color=green][color=darkred]
          >>> s | t[/color][/color][/color]
          set(['sesame', 'plugh', 'mellon', 'xyzzy'])[color=blue][color=green][color=darkred]
          >>> (s | t) - t[/color][/color][/color]
          set(['sesame'])[color=blue][color=green][color=darkred]
          >>> (s | t) - s[/color][/color][/color]
          set(['mellon'])[color=blue][color=green][color=darkred]
          >>>[/color][/color][/color]

          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

          Comment

          • Tim Chase

            #6
            Re: comparing values in two sets

            > I'd like to compare the values in two different sets to[color=blue]
            > 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).[/color]

            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:
            [color=blue][color=green][color=darkred]
            >>> set([1,3,5,7,9])[/color][/color][/color]
            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

            Comment

            • Paul Rubin

              #7
              Re: comparing values in two sets

              John Salerno <johnjsal@NOSPA Mgmail.com> writes:[color=blue]
              > 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).[/color]

              I think by "sets" you mean "lists". Sets are unordered, as a few
              people have mentioned.
              [color=blue]
              > I have this:
              >
              > def test_sets(origi nal_set, trans_letters):
              > for pair in zip(original_se t, trans_letters):
              > if pair[0] == pair[1]:
              > return False
              > return True[/color]

              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(origi nal_set, trans_letters):
              for i in xrange(len(orig inal_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(origi nal_set, trans_letters):
              return not sum(a==b for a,b in izip(original_s et, 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.

              Comment

              • John Salerno

                #8
                Re: comparing values in two sets

                John Salerno wrote:[color=blue]
                > I'd like to compare the values in two different sets[/color]

                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. :)

                Comment

                • Peter Otten

                  #9
                  Re: comparing values in two sets

                  Paul Rubin wrote:
                  [color=blue]
                  > You could even get cutesy and say something like (untested):
                  >
                  > from itertools import izip
                  > def test_sets(origi nal_set, trans_letters):
                  > return not sum(a==b for a,b in izip(original_s et, 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.[/color]

                  Here's a variant that does performs only the necessary tests:
                  [color=blue][color=green][color=darkred]
                  >>> from itertools import izip
                  >>> True not in (a == b for a, b in izip(range(3), range(3)))[/color][/color][/color]
                  False

                  A "noisy" equality test to demonstrate short-circuiting behaviour:
                  [color=blue][color=green][color=darkred]
                  >>> def print_eq(a, b):[/color][/color][/color]
                  .... print "%r == %r --> %r" % (a, b, a == b)
                  .... return a == b
                  ....[color=blue][color=green][color=darkred]
                  >>> True not in (print_eq(a, b) for a, b in izip(range(3), range(3)))[/color][/color][/color]
                  0 == 0 --> True
                  False[color=blue][color=green][color=darkred]
                  >>> True not in (print_eq(a, b) for a, b in izip(["x", 1, 2], range(3)))[/color][/color][/color]
                  'x' == 0 --> False
                  1 == 1 --> True
                  False[color=blue][color=green][color=darkred]
                  >>> True not in (print_eq(a, b) for a, b in izip(["x", "x", "x"], range(3)))[/color][/color][/color]
                  'x' == 0 --> False
                  'x' == 1 --> False
                  'x' == 2 --> False
                  True

                  Peter

                  Comment

                  • Paul Rubin

                    #10
                    Re: comparing values in two sets

                    Peter Otten <__peter__@web. de> writes:[color=blue]
                    > Here's a variant that does performs only the necessary tests:
                    >[color=green][color=darkred]
                    > >>> from itertools import izip
                    > >>> True not in (a == b for a, b in izip(range(3), range(3)))[/color][/color][/color]

                    Cute!

                    Comment

                    • Gerard Flanagan

                      #11
                      Re: comparing values in two sets

                      John Salerno wrote:[color=blue]
                      > 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(origi nal_set, trans_letters):
                      > for pair in zip(original_se t, 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.[/color]

                      'enumerate' is another possibility:

                      s1 = 'abcd'
                      s2 = 'zzzz'
                      s3 = 'zbzz'
                      s4 = 'zzbz'

                      def are_itemwise_di fferent( 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_di fferent( 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_di fferent(s1,s2)
                      assert not are_itemwise_di fferent(s1,s3)
                      assert are_itemwise_di fferent(s1,s4)

                      def itemwise_inters ect( L1, L2 ):
                      #if len(L1) != len(L2): raise
                      for idx, value in enumerate(L1):
                      if value == L2[idx]:
                      yield value

                      assert list(itemwise_i ntersect(s1,s2) ) == []
                      assert list(itemwise_i ntersect(s1,s3) ) == ['b']
                      assert list(itemwise_i ntersect(s1,s4) ) == []

                      Gerard

                      Comment

                      • Gerard Flanagan

                        #12
                        Re: comparing values in two sets


                        Gerard Flanagan wrote:[color=blue]
                        > John Salerno wrote:[color=green]
                        > > 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(origi nal_set, trans_letters):
                        > > for pair in zip(original_se t, 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.[/color]
                        >
                        > 'enumerate' is another possibility:
                        >
                        > s1 = 'abcd'
                        > s2 = 'zzzz'
                        > s3 = 'zbzz'
                        > s4 = 'zzbz'
                        >
                        > def are_itemwise_di fferent( 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_di fferent( L1, L2 ):
                        > return True not in ( val == L2[idx] for idx, val in enumerate(L1) )
                        >
                        > assert are_itemwise_di fferent(s1,s2)
                        > assert not are_itemwise_di fferent(s1,s3)
                        > assert are_itemwise_di fferent(s1,s4)
                        >[/color]

                        s1 = 'abcd'
                        s2 = 'zzzz'
                        s3 = 'zbzz'
                        s4 = 'zzbz'
                        s5 = 'xbxx'

                        def itemwise_inters ect( L1, L2 ):
                        return [value for idx, value in set(enumerate(L 1)) &
                        set(enumerate(L 2))]

                        assert itemwise_inters ect(s1,s2) == []
                        assert itemwise_inters ect(s1,s3) == ['b']
                        assert itemwise_inters ect(s1,s4) == []

                        def itemwise_inters ect( *args ):
                        s = set(enumerate(a rgs[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_inters ect(s1,s3,s5) == ['b']

                        Gerard

                        Comment

                        Working...