# adj_pairs_many_many_variants.py # D. Gries (djg17), L. Lee (LJL2), S. Marschner (srm2), W. White (wmw2) # April 10, 2014 """Different versions of the same goal: a function that takes a string s as argument and returns the number of equal adjacent pairs in it. The different versions are based on different invariants, or while vs. for The application code tests the various functions on the same few inputs.""" # If you want to try writing these things given just the invariant, make a copy # of this file and remove all lines between pairs of "# BEGIN REMOVE" and # "# END REMOVE" comments. def ap1(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## While loop; see invariant x = None # stub # BEGIN REMOVE x = 0 k = 1 # END REMOVE # inv: x = # adjacent equal pairs in s[0..k-1] # (so k = next index to check for ending an adjacent pair) # BEGIN REMOVE while k < len(s): if (verbose): print ' in ap1 loop. There are', x, 'pairs in', s[0:k] x += (1 if s[k-1] == s[k] else 0) # alternately: x += (s[k-1] == s[k]) k += 1 # post: x = # adjacent equal pairs in s[0..len(s)-1] # END REMOVE return x # BEGIN REMOVE def ap1a(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## While loop with same invariant as ap1 but increment in different place x = 0 k = 1 # inv: x = # adjacent equal pairs in s[0..k-1] # (so k = next index to check for ending an adjacent pair) while k < len(s): if (verbose): print ' in ap1a loop. There are', x, 'pairs in', s[0:k] k += 1 x += (s[k-2] == s[k-1]) return x # END REMOVE def ap2(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## While loop; see invariant x = None # stub # set x to # adjacent equal pairs in s[0..len(s)-1] # BEGIN REMOVE x = 0 j = 0 # END REMOVE # inv: x = # adjacent equal pairs in s[0..j] # (so j = next index to check for starting an adjacent pair) # BEGIN REMOVE while j < len(s)-1: if (verbose): print ' in ap2 loop. There are', x, 'pairs in', s[0:j+1] x += (s[j]==s[j+1]) j += 1 # x = # adjacent equal pairs in s[0..len(s)-1] # END REMOVE return x def ap2a(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## While loop; same invariant as ap2 but increment is before update x = None # stub # set x to # adjacent equal pairs in s[0..len(s)-1] # BEGIN REMOVE x = 0 j = 0 # END REMOVE # inv: x = # adjacent equal pairs in s[0..j] # (so j = next index to check for starting an adjacent pair) # BEGIN REMOVE while j < len(s)-1: if (verbose): print ' in ap2a loop. There are', x, 'pairs in', s[0:j+1] j += 1 x += (s[j-1] == s[j]) # post: x = # adjacent equal pairs in s[0..len(s)-1] # END REMOVE return x def ap3(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## For loop; see invariant and note the for-loop list's "end" point x = None # stub # set x to # adjacent equal pairs in s[0..len(s)-1] # BEGIN REMOVE x = 0 # END REMOVE # inv: x = # adjacent equal pairs in s[0..m] # (where m = next index to check for starting an adjacent pair) # BEGIN REMOVE for m in range(len(s)-1): # so last value is len(s) - 2 if (verbose): print ' in ap3 loop. There are', x, 'pairs in', s[0:m+1] x += (s[m] == s[m+1]) # x = # adjacent equal pairs in s[0..len(s)-1] # END REMOVE return x def ap4(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## For loop; see invariant and note the for-loop list's "begin" point x = None # stub # set x to # adjacent equal pairs in s[0..len(s)-1] # BEGIN REMOVE x = 0 # END REMOVE # inv: x = # adjacent equal pairs in s[0..m-1] # (where m = next index to check for ending an adjacent pair) # BEGIN REMOVE for m in range(1, len(s)): # so last value is len(s) - 1 if (verbose): print ' in ap4 loop. There are', x, 'pairs in', s[0:m] x += (s[m-1] == s[m]) # x = # adjacent equal pairs in s[0..len(s)-1] # END REMOVE return x def ap5(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## While loop that works backwards x = None # stub # BEGIN REMOVE x = 0; m = len(s) - 1 # END REMOVE # inv: x = # adjacent equal pairs in s[m..len(s)-1], m-1 is next thing to # check for beginning an adjacent pair # BEGIN REMOVE while m >= 1: if (verbose): print ' in ap5 loop. There are', x, 'pairs in', s[m:len(s)] x += (s[m-1] == s[m]) m -= 1 # END REMOVE return x def ap5a(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## While loop that works backwards, ap5 inv but increment at diff time x = None # stub # BEGIN REMOVE x = 0; m = len(s) - 2 # END REMOVE # inv: x = # adjacent equal pairs in s[m+1..len(s)-1], m is next thing to # check for beginning an adjacent pair # BEGIN REMOVE while m >= 0: if (verbose): print ' in ap5a loop. There are', x, 'pairs in', s[m+1:len(s)] m -= 1 x += (s[m+1] == s[m+2]) # END REMOVE return x def ap6(s, verbose=False): """Returns: number of adjacent equal pairs in string s. Case counts. Prints out extra info if and only if verbose is True""" ## While loop that works backwards, see invariant x = None # stub # BEGIN REMOVE x = 0; m = len(s) - 1 # END REMOVE # inv: x = # adjacent equal pairs in s[m..len(s)-1], m is next thing to # check for ending an adjacent pair # BEGIN REMOVE while m >= 1: if (verbose): print ' in ap6 loop. There are', x, 'pairs in', s[m:len(s)] x += (s[m-1] == s[m]) m -= 1 # END REMOVE return x if __name__ == '__main__': ins = ['abc', '', 'ebee', 'ebeee', 'aaee'] outs = [0 , 0, 1, 2, 2] verbosity = [False, False, False, False, False] # verbosity[i]: whether to have fns print diagnostic info for ins[i] for fn in [ap1, ap1a, ap2, ap2a, ap3, ap4, ap5, ap5a, ap6]: print 'testing ' + fn.__name__ for i in range(len(ins)): fnout = fn(ins[i], verbosity[i]) print ' input was ' + ins[i] + ', output was ' + str(fnout) + \ (' which was right.' if fnout == outs[i] else (' NOT ' + str(outs[i]))) print 'all test cases have been run'