Computer Science 15-112, Spring 2013
Class Notes:  One-Dimensional Lists Redux


  1. zip and unzip
  2. List Comprehensions
  3. Miscellaneous Topics
  4. Lists and Strings
    1. Converting between lists and strings
    2. Using Lists to Avoid Inefficiencies of Strings

  1. zip and unzip
    a = [1, 2, 3, 4]
    b = [5, 6, 7, 8]
    c = zip(a,b)
    print c  # [(1, 5), (2, 6), (3, 7), (4, 8)]
    
    (aa,bb) = zip(*c)  # strange syntax, but this unzips c
    print aa  # (1, 2, 3, 4)
    print bb  # (5, 6, 7, 8)
    
    print ((aa == a) and (bb == b))               # False
    print ((aa == tuple(a)) and (bb == tuple(b))) # True
  2. List Comprehensions
    # Examples from http://www.python.org/dev/peps/pep-0202/
    
    print [i for i in range(10)]
    # prints:
    #    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    print [i for i in range(20) if i%2 == 0]
    # prints:
    #    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    
    # Note: just because you can do some of these more exotic things,
    # does not mean you necessarily should!  Clarity above all!
    
    nums = [1,2,3,4]
    fruit = ["Apples", "Peaches", "Pears", "Bananas"]
    print [(i,f) for i in nums for f in fruit]
    # prints:
    #    [(1, 'Apples'), (1, 'Peaches'), (1, 'Pears'), (1, 'Bananas'),
    #     (2, 'Apples'), (2, 'Peaches'), (2, 'Pears'), (2, 'Bananas'),
    #     (3, 'Apples'), (3, 'Peaches'), (3, 'Pears'), (3, 'Bananas'),
    #     (4, 'Apples'), (4, 'Peaches'), (4, 'Pears'), (4, 'Bananas')]
    
    print [(i,f) for i in nums for f in fruit if f[0] == "P"]
    # prints:
    #    [(1, 'Peaches'), (1, 'Pears'),
    #     (2, 'Peaches'), (2, 'Pears'),
    #     (3, 'Peaches'), (3, 'Pears'),
    #     (4, 'Peaches'), (4, 'Pears')]
    
    print [(i,f) for i in nums for f in fruit if f[0] == "P" if i%2 == 1]
    # prints:
    #    [(1, 'Peaches'), (1, 'Pears'), (3, 'Peaches'), (3, 'Pears')]
    
    print [i for i in zip(nums,fruit) if i[0]%2==0]
    # prints:
    #    [(2, 'Peaches'), (4, 'Bananas')]
  3. Miscellaneous Topics
    1. list.reverse() and reversed(list)
    2. Safely using list.index(item) with try/except
    3. Other ways to...
      1. Remove Items from a List
        1. list[a:b] = [ ]
        2. del list[a:b]
      2. Copy a List
        1. list2 = list1[:]
        2. list2 = list1 + [ ]
        3. list2 = list(list1)
        4. list2 = copy.deepcopy(list1)
        5. list2 = sorted(list1)
    4. list.sort(compareFn)
      def cmp(s1, s2):
          # compare s1 and s2
          # result > 0   ==>  s1 > s2
          # result == 0  ==>  s1 == s2
          # result < 0   ==>  s1 < s2
          return int(s1) - int(s2)
      
      s = ["1", "2", "12", "23", "123"]
      s.sort()
      print s  # prints ['1', '12', '123', '2', '23']
      s.sort(cmp)
      print s  # ['1', '2', '12', '23', '123']
  4. Lists and Strings 
    1. Converting between lists and strings
      # use list(s) to convert a string to a list of characters
      a = list("wahoo!")
      print a  # prints: ['w', 'a', 'h', 'o', 'o', '!']
      
      # use "".join(a) to convert a list of characters to a single string
      s = "".join(a)
      print s  # prints: wahoo!
      
      # "".join(a) also works on a list of strings (not just single characters)
      a = ["parsley", " ", "is", " ", "gharsley"] # by Ogden Nash!
      s = "".join(a)
      print s  # prints: parsley is gharsley
    2. Using Lists to Avoid Inefficiencies of Strings
      Note:  the efficiency of various operations in Python depends heavily on what version of Python you are running, and on what platform (Windows, Mac, Linux) you are running it.  As a general rule, creating strings is expensive.  In many other programming languages, this is especially true.  However, for some versions of Python on some platforms, creating lists can be equally as expensive.  The examples below show the difference in speeds.  On most platforms, the string-based solutions are slower, but on some, they are faster.
       
      1. Repeatedly modifying a single string
        # If you are going to repeatedly "change" a string (in quotes,
        # because you cannot change strings, so instead you'll create lots
        # of new strings, which immediately become garbage),
        # it can be faster to first convert the string to a list,
        # change the list (which is mutable), and then convert back
        # to a string at the end.  Check this out:
        
        import time
        
        print "*****************"
        print "First, change the string the slow way..."
        n = 12345678
        start0 = time.time()
        s0 = "abcdefg"
        for count in xrange(n):
            c = "z" if s0[3] == "d" else "d"
            s0 = s0[0:3] + c + s0[4:]
        elapsed0 = time.time() - start0
        print "Total time:", elapsed0
        
        print "*****************"
        print "Next, the faster way..."
        start1 = time.time()
        s1 = "abcdefg"
        a = list(s1)
        for count in xrange(n):
            c = "z" if a[3] == "d" else "d"
            a[3] = c # this is the magic line we could not do above!
        s1 = "".join(a)
        elapsed1 = time.time() - start1
        print "Total time:", elapsed1
        
        print "*****************"
        print "Analysis..."
        print "Two approaches work the same:", (s0 == s1)
        print "But the second approach runs %0.1f times faster!" % (elapsed0/elapsed1)
      2. Concatenating a large number of strings
        # It can be much faster to join strings in a list than to concatenate
        # them one-at-a-time.  Again, though, it is version- and platform-dependent.
        
        import time
        
        print "*****************"
        print "First, concatenate numbers (as strings) the slow way..."
        n = 1234567
        start0 = time.time()
        s0 = ""
        for i in xrange(n):
            s0 += str(i)
        elapsed0 = time.time() - start0
        print "Total time:", elapsed0
        
        print "*****************"
        print "Next, concatenate numbers (as strings) the faster way..."
        start1 = time.time()
        listOfStrings = [ ]
        for i in xrange(n):
            listOfStrings += [str(i)]
        s1 = "".join(listOfStrings)
        elapsed1 = time.time() - start1
        print "Total time:", elapsed1
        
        print "*****************"
        print "Analysis..."
        print "Two approaches work the same:", (s0 == s1)
        print "But the second approach runs %0.1f times faster!" % (elapsed0/elapsed1)

carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem