Python Efficiency Help

For the discussion of Perl, Python, Ruby, and PHP and other interpreted languages.

Python Efficiency Help

Post by kg-infinite on Wed Mar 13, 2013 7:26 pm
([msg=74520]see Python Efficiency Help[/msg])

Hi, I've been learning Python and I am new to coding and stuff... Could someone take a look at what I've done and try to help me make it more efficient? I didn't want to come here for help until I was able to achieve the desired results on my own. However, I highly doubt I've done the goals the most efficient way. This is from Google Python Exercises that I saw on YouTube... The code has the directions and everything in it.

I appreciate all the help I can get, thanks...

Need help checking the following Functions for efficiency: D. verbing, E. not_bad, F. front_back

Code: Select all
#!/usr/bin/python2.4 -tt
# Copyright 2010 Google Inc.
# Licensed under the Apache License, Version 2.0
# http://www.apache.org/licenses/LICENSE-2.0

# Google's Python Class
# http://code.google.com/edu/languages/google-python-class/

# Additional basic string exercises

# D. verbing
# Given a string, if its length is at least 3,
# add 'ing' to its end.
# Unless it already ends in 'ing', in which case
# add 'ly' instead.
# If the string length is less than 3, leave it unchanged.
# Return the resulting string.
def verbing(s):
  if len(s) >= 3 and s[-3:] != 'ing':
    s += 'ing'
  elif len(s) >= 3 and s[-3:] == 'ing':
    s += 'ly'
  return s


# E. not_bad
# Given a string, find the first appearance of the
# substring 'not' and 'bad'. If the 'bad' follows
# the 'not', replace the whole 'not'...'bad' substring
# with 'good'.
# Return the resulting string.
# So 'This dinner is not that bad!' yields:
# This dinner is good!
def not_bad(s):
  count = -1
  count1 = 0
  count2 = 0
  wordnot = 'false'
  wordbad = 'false'
  for x in s:
    count += 1
    if s[count:count + 3] == 'not':
      count1 = count
      wordnot = 'true'
    if s[count:count + 3] == 'bad':
      count2 = count + 3
      wordbad = 'true'
  if wordnot == 'true' and wordbad == 'true' and count1 < count2:
    finalstring = s[:count1] + 'good' + s[count2:]
  else:
    finalstring = s
  return finalstring


# F. front_back
# Consider dividing a string into two halves.
# If the length is even, the front and back halves are the same length.
# If the length is odd, we'll say that the extra char goes in the front half.
# e.g. 'abcde', the front half is 'abc', the back half 'de'.
# Given 2 strings, a and b, return a string of the form
#  a-front + b-front + a-back + b-back
def front_back(a, b):
  afront = ''
  aback = ''
  bfront = ''
  bback = ''
  for x in a:
    if len(afront) < len(a)/2 and len(a)%2 == 0:
      afront += x
    elif len(afront) <= len(a)/2 and len(a)%2 != 0:
      afront += x
    else:
      aback += x
  for y in b:
    if len(bfront) < len(b)/2 and len(b)%2 == 0:
      bfront += y
    elif len(bfront) <= len(b)/2 and len(b)%2 != 0:
      bfront += y
    else:
      bback += y
  finalstring = afront + bfront + aback + bback
  return finalstring


# Simple provided test() function used in main() to print
# what each function returns vs. what it's supposed to return.
def test(got, expected):
  if got == expected:
    prefix = ' OK '
  else:
    prefix = '  X '
  print '%s got: %s expected: %s' % (prefix, repr(got), repr(expected))


# main() calls the above functions with interesting inputs,
# using the above test() to check if the result is correct or not.
def main():
  print 'verbing'
  test(verbing('hail'), 'hailing')
  test(verbing('swiming'), 'swimingly')
  test(verbing('do'), 'do')

  print
  print 'not_bad'
  test(not_bad('This movie is not so bad'), 'This movie is good')
  test(not_bad('This dinner is not that bad!'), 'This dinner is good!')
  test(not_bad('This tea is not hot'), 'This tea is not hot')
  test(not_bad("It's bad yet not"), "It's bad yet not")

  print
  print 'front_back'
  test(front_back('abcd', 'xy'), 'abxcdy')
  test(front_back('abcde', 'xyz'), 'abcxydez')
  test(front_back('Kitten', 'Donut'), 'KitDontenut')

if __name__ == '__main__':
  main()
kg-infinite
New User
New User
 
Posts: 1
Joined: Wed Mar 13, 2013 7:23 pm
Blog: View Blog (0)


Re: Python Efficiency Help

Post by cberg22 on Wed Mar 13, 2013 9:14 pm
([msg=74527]see Re: Python Efficiency Help[/msg])

I haven't had time to look through the whole thing, but will later. For now, in the verbing function, you are checking if the word is 3 characters or more and if it ends in 'ing' twice if the first if statement is false. Instead, you can use a nested if to first check the length then check the last 3 characters only if the length is sufficient. This means that if the word is less than 3 characters, it will return the word straight away with no more computation, and even if it is more, it will only check the last 3 characters once regardless of them being 'ing' or not.

Code: Select all
def verbing(s):
  if len(s) >= 3:
    if s[-3:] != 'ing':
      s += 'ing'
    else:
      s += 'ly'
  return s
cberg22
New User
New User
 
Posts: 7
Joined: Wed Feb 13, 2013 7:29 am
Blog: View Blog (0)


Re: Python Efficiency Help

Post by cyberdrain on Tue Apr 16, 2013 12:41 am
([msg=75141]see Re: Python Efficiency Help[/msg])

I tried some coding myself, but it's probably not the fastest way. According to timeit it's about 8 times as fast as the method you used, except for the 3rd string ('This tea is not hot'), which is only twice as fast.

Code: Select all
def not_bad1(s):
  try:
    count1 = s.index("not")
    count2 = s.index("bad")
  except ValueError:
    return s
  else:
    if count1 < count2:
      return s[:count1] + 'good' + s[count2 + 3:]
    else:
      return s

I could reduce the time of the third string by about 90% with only about 5% increase to the other functions:
Code: Select all
def not_bad2(s):
  if "not" in s and "bad" in s:
    count1 = s.index("not")
    count2 = s.index("bad")
    if count1 < count2:
      return s[:count1] + 'good' + s[count2 + 3:]
    else:
      return s

As always it depends on which string you are more likely to send to the function and plan accordingly. For the frontback function I'd advise only doing the maths once and then use the index found like above (string[from:to]). The for loop should be avoided whenever possible, as Python is interpreted. The index function for example does the for loop for you, but not in interpreted Python, so it's a lot faster.
Free your mind / Think clearly
User avatar
cyberdrain
Addict
Addict
 
Posts: 1358
Joined: Sun Nov 27, 2011 1:58 pm
Blog: View Blog (0)


Re: Python Efficiency Help

Post by deepWithin on Wed Apr 17, 2013 9:20 am
([msg=75186]see Re: Python Efficiency Help[/msg])

If you downloaded the scripts from: https://developers.google.com/edu/pytho ... ises/basic there is actually a solution folder which shows you efficient ways of doing the exercises.
deepWithin
New User
New User
 
Posts: 3
Joined: Wed Apr 10, 2013 12:32 pm
Blog: View Blog (0)



Return to Interpreted Languages

Who is online

Users browsing this forum: No registered users and 0 guests