Python: how to optimize this code for better performance - python

I use this code to syllable a list of strings, I need to be able to speed up this code to pass some tests, any ideas to improve this code and make it faster?
def separate(word):
s = ""
L = []
voc = ['a','e','i','o','u','y','j']
for letter in word:
if len(s) < 1:
s += letter
elif s[len(s) - 1] not in voc:
s += letter
elif s.startswith('aeiouyj'):
s +=letter
elif letter in voc:
s += letter
else:
L.append(s)
s = letter
L.append(s)
return L

Did some small misc adjustments.
def separate(word):
s=''
L = []
for letter in word:
if s=='':
s = letter
elif s[-1] not in 'aeiouyj' or letter in 'aeiouyj':
s += letter
else:
L.append(s)
s = letter
L.append(s)
return L
Not sure if s.startswith('aeiouyj') is of any use in original code because it never going to be True.

def separate(word):
s = ""
L = []
voc = ['a','e','i','o','u','y','j']
s=word[0]
for letter in word[1:]:
if s[len(s) - 1] not in voc:
s += letter
elif letter in voc or s.startswith('aeiouyj'):
s +=letter
else:
L.append(s)
s = letter
L.append(s)
return L
After analysing the code, we can see that it is going into first if just in the beginning. So, we can skip this part. One more thing you can do bring the if before last else to the second place. After analysing a Harry Potter paragraph with this program it enters into loops "1,2436,0,98,959" times respectively. The third if maybe eliminated too, since it never entered into this branch in my case.

Instead of using loops you can use recursion which is faster than it. Also Functional programming is always preferred as it is based on input.

Related

How to capitalize 1st and 4th characters of a string?

OLD MACDONALD: Write a function that capitalizes the first and fourth letters of a name
I'm trying to write this in different ways and I also feel like there's an easier way to do this. Cant, you directly apply it without getting all the other words of a string? Or a split or something?
Here is one of my attempts at trying it another way. I'm trying to do it with a for AND an if statement too. Any help is appreciated.
def old_macdonald(words):
wordletter = words[0]
fourthletter = words[3]
newword = []
for i,l in enumerate(words):
if i[0]:
newword = l.capatalize
return newword
if i[3]:
newword = l.capatalize
return newword
This is the most legible way IMO
def old_macdonald(name):
mylist = list(name)
mylist[0] = mylist[0].upper()
mylist[3] = mylist[3].upper()
return ''.join(mylist)
def old_macdonald(name):
letters = list(name)
for index in range(len(name)):
if index == 0:
letters[index] = letters[index].upper()
elif index == 3:
letters[index] = letters[index].upper()
return "".join(letters)
This one worked for me
this code will make first and forth element of the string Capital.
def cap(name):
first = name[0]
mid = name[1:3]
second = name[3]
rest = name[4:]
return first.upper() + mid + second.upper() + rest
cap('kahasdfn')
Here's one way. You do need to split the string into a list of characters to change individual characters, because strings are immutable, and then use join afterward to convert them back into a string.
def old_macdonald(name):
letters = list(name)
for letter_to_capitalize in [1, 4]:
if len(letters) >= letter_to_capitalize:
letters[letter_to_capitalize - 1] = letters[letter_to_capitalize - 1].upper()
return "".join(letters)
A pretty simple and modifiable example.
def old_mcdonald(word):
indexes = (0,3) #letters i want to cap
new_word = "".join([v.capitalize() if i in indexes else v for i,v in enumerate(word)])
return new_word
def old_macdonald(s):
return ''.join([s[:1].upper(), s[1:3], s[3:4].upper(), s[4:]])
# s[:1] - letter index 0 (first)
# s[1:3] - letters index 1-2
# s[3:4] - letter index 3 (fourth)
# s[4:] - letters index 4 onward
test_string = "abcdefghijklmnopqr"
print(old_macdonald(test_string )) # AbcDefghijklmnopqr
I like writing it this way:
def old_macdonald(word):
indices = (0, 4)
return ''.join(c.capitalize() if index in indices else c for index, c in enumerate(word))
Although it's a little long, so you might prefer writing it more clearly as:
def old_macdonald(word):
indices = (0, 4)
new_string = []
for index, c in enumerate(word):
new_string.append(c.capitalize() if index in indices else c)
return ''.join(new_string)
def old_macdonald(s):
w=""
for i in s:
t=s.index(i)
if t==0:
w=w+i.upper()
elif(t==3):
w=w+i.upper()
else:
w=w+i
print(w)
old_macdonald("aman")
def old_macdonald(s):
return s[0:3].capitalize() + s[3:].capitalize()
https://ideone.com/2D0qbZ
This one worked
def old_macdonald(name):
word = ''
for index,letter in enumerate(name):
if index == 0 or index == 3:
letter = name[index].capitalize()
word += letter
else:
word += letter
return word

How to fix a String index out of range exception in Python

There is some issue with my python code. I am making a program that finds the occurrences of the letter A in a word and if that letter is found and the next letter is not the letter A the A is swapped with the next letter.
As an example TAN being TNA but WHOA staying as WHOA
AARDVARK being ARADVRAK
The issue is when I input ABRACADABRA I get a string index out of range exception. Before I had that exception I had the word that prints it as BRACADABRIi'm not sure why if I have to add another loop in my program.
If you guys also have anymore efficient way to run the code then the way I have please let me know!
def scrambleWord(userInput):
count = 0
scramble = ''
while count < len(userInput):
if userInput[count] =='A' and userInput[count+1] != 'A':
scramble+= userInput[count+1] + userInput[count]
count+=2
elif userInput[count] != 'A':
scramble += userInput[count]
count+=1
if count < len(userInput):
scramble += userInput(len(userInput)-1)
return scramble
#if a is found switch the next letter index with a's index
def main():
userInput = input("Enter a word: ")
finish = scrambleWord(userInput.upper())
print(finish)
main()
When you get to the end of the string and it is an 'A' your program is then asking for the next character which is off the end of the string.
Change the loop so it doesn't include the last character:
while count < len(userInput)-1:
if ...
You can modify your code as below:
def scrambleWord(userInput):
count = 0
scramble = ''
while count < len(userInput):
if count < len(userInput)-1 and userInput[count] =='A' and userInput[count+1] != 'A':
scramble+= userInput[count+1] + userInput[count]
count+=2
else:
scramble += userInput[count]
count+=1
return scramble
You are not checking the condition (count < len(userInput)-1) when logic tries to check for A's occurrence and swap with next letter. It throws string index out of range exception.
The issue arises in your code when last character in input is 'A'.
This is because your first if in the loop tries to access 'count + 1' character during last iteration.
And since there's no character at that position, you get index error.
The simplest solution would be to make a separate if condition for the same.
Updated snippet for while loop might look like this -
# while start
while count < len_: # len_ is length of input
if count + 1 >= len_:
break # break outta loop, copy last character
current = inp[count]
next_ = inp[count + 1]
if current == 'A':
op += ( next_ + current) # op is result
count += 1
else:
op += current
# increment counter by 1
count += 1
# rest of the code after while is same
Another small issue in your code is while copying last character ( after loop ends ), you should use [ ] instead of ( ) to refer last character in input string.
Just for fun :
from functools import reduce
def main():
word = input("Enter a word: ").lower()
scramble = reduce((lambda x,y : x[:-1]+y+'A' \
if (x[-1]=='a' and y!=x[-1]) \
else x+y),word)
print(scramble.upper())
main()

Create a function that contains only the first occurrence of a letter from the original phrase

The function needs to behave as follow:
The first letter occurrence can be upper or lower case (newPhrase).
Non-alpha characters - are left unchanged.
So far I thought of :
def keepFirstLetter(phrase):
'''Returns a new string that contains only the first occurrence of a
letter from the original phrase.
letterSeenSoFar = ''
newPhrase = ''
if (letterSeenSoFar == '' or letterSeenSoFar[-1] != letterSeenSoFar):
letterSeenSoFar += c
for letter in letterSeenSoFar:
if letter.isalpha:
newPhrase += char
else:
newPhrase += letter
return newPhrase
You seem to be on the right track. If you want to improve you efficiency, you can store the seen letters as a set. Searching a set is O(1).
def unique_first(s):
letters = set()
out = ''
for x in s:
if not x.isalpha():
out += x
continue
if not x.lower() in letters:
out += x
letters.add(x.lower())
return out
The most straightforward, sure-to-have-learned solution is probably:
def keepFirstLetter(phrase):
output = ''
for letter in phrase:
if (letter.lower() not in output.lower()) or (not letter.isalpha()):
output += letter
return output
print(keepFirstLetter('Amy says, "Me?"')) # Amy s, "e?"
(the parens around the two if clauses are optional)
James's solution still gets my vote though.
My name was in the question so let me take a try.
I learned set.add() from James for the first time. (Thank you, James.) James' code is shorter and runs faster (3.48us vs. 3.76us on my PC).
def keepFirstLetter(phrase):
phrase = list(phrase)
'''Returns a new string that contains only the first occurrence of a
letter from the original phrase.'''
letterSeenSoFar = []
newPhrase = ''
for char in phrase:
# if char is not an alphabet, add char to the newPhrase as is
if not char.isalpha():
newPhrase += char
# if char is an alphabet and not seen so far, add char to the newPhrase and append it to letterSeenSoFar
elif char.lower() not in letterSeenSoFar:
letterSeenSoFar.append(char.lower())
newPhrase += char
return newPhrase
print(keepFirstLetter('Amy says, " Me?"'))
This outputs:
Amy s, " e?"

How to count the number of vowels in a string without a function wrapper

I've currently solving a MIT undergrad problem in Python 3.5.
The goal is to write a Python script counting and printing the number of vowels in a string containing only lower-case letters without using a function wrapper or even a function definition (stated in the assignment, weird ?).
def vowels_count(s):
i=0
counter = 0
while(s[i] != " "):
if s[i] == "a" or s[i] == "e" or s[i] == "i" or s[i] == "o" or s[i] == "u":
counter += 1
i = i + 1
return(counter)
I have two problems:
1/ first of, my own code using a while do structure meets a problem with the use of the index navigating from the first character to the last one. The debugger says: index out of range
2/ finally, if I have to comply with the MIT instructions, I would not be able to do anything in a single-line code without defining a function.
Thanks for your support
Why is this version not correct on the string index i ?
def vowels_count_1(s):
i = 0
counter = 0
while(s[i] != ""):
if s[i] == "a" or s[i] == "e" or s[i] == "i" or s[i] == "o" or s[i] == "u":
counter += 1
i += 1
print("Number of vowels: " + str(counter))
You can use the condition of i being less than the length of your string to break out of the while loop. I also recommend the easier approach of just checking if the letter at s[i] is in a string composed of vowels:
def vowels_count(s):
i = 0
counter = 0
while i < len(s):
if s[i] in 'aeiou':
counter += 1
i += 1
return counter
If you wanted to do this in one line, you could use the length of a list comprehension:
counter = len([c for c in s if c in 'aeiou'])
As you learn more and more you'll be able to count the vowels in one line using sum and a generation expression.
You could fix your loop while i < len(s), i.e. up to the length of the string, but much better is just to iterate over the sequence of characters we call "string".
for ch in s:
if ch == 'a' or ...
No indices needed. No i.
If you have learned the in operator already, you could simplify the test.
Without a function probably means this:
s = "the string"
# your code here
print("vowel count:", counter)
But I'm not sure ...
Here is an one line solution:
reduce(lambda t, c : (t + 1) if c in 'aeiou' else t, s.lower(), 0)

My anagram code doesn't account for multiple letters

So my code gets two words, and checks if one is the anagram of another one.
However doesn't work if multiple letters are exchanged, although I tried to account for that.
storedword = input("Enter your primary word \t")
global word
word = list(storedword)
word3 = input("Enter anagram word \t")
word3lowercase = word3.lower()
anaw = list(word3lowercase)
counter = int(0)
letterchecker = int(0)
listlength = len(word)
newcounter = int(0)
if len(anaw) != len(word):
print ("not anagram")
if len(anaw) == len(word):
while counter < listlength and newcounter < listlength:
tempcount = 0
if anaw[counter] == word[newcounter]:
temp = word[newcounter]
word[newcounter] = word[tempcount]
word[tempcount]=temp
letterchecker +=1
counter +=1
tempcount +=1
newcounter = int(0)
else:
newcounter +=1
if counter == len(word):
print ("anagram")
else:
print ("not anagram")
I think it's gone somewhere wrong after the if len(anaw) section, for example if the primary word is "hannah", and the secondary word is "hannnn", it thinks it's an anagram.
There is much simpler logic that can be implemented here, even without using sorted and such. Let's assume you have a function anagram:
def anagram(word1, word2):
if len(word1) != len(word2):
return False
def char_count(word):
char_count = {}
for c in word:
char_count[c] = char_count.get(c, 0) + 1
return char_count
cr1 = char_count(word1)
cr2 = char_count(word2)
return cr1 == cr2
You can test this with:
>>> print(anagram("anagram", "aanragm"))
True
>>> print(anagram("anagram", "aangtfragm"))
False
And for future readers, a super simple pythonic solution might be using Counter:
from collections import Counter
>>> Counter(word1) == Counter(word2)
Or using sorted:
>>> sorted(word1) == sorted(word2)
newcounter = int(0)
This is the line that causes the trouble (in the while loop).
Because of it you start checking the word from the beginning again.
I think you want it to be newcounter=letterchecker.
Since already used characters are put to the front of word they are ignored if you start with letterchecker
Tell me if it works
Edit:Checked with example given, seems to work.
Without using sort you could use the following approach. It removes a letter from an array of a characters of the second word. The words are only anagrams if there are no letters left (and the words are the same length to start with and have a length larger than zero):
word1="hannah"
word2="nahpan"
chars1= list(word1)
chars2= list(word2)
if len(chars1)==len(chars2) and len(chars1)>0:
for char in chars1:
if char not in chars2:
break
chars2.remove(char)
if len(chars2)==0:
print "Both words are anagrams"
else:
print "Words are not anagrams"
[EDIT THIS IS JUST FOR PALINDROMES I CANT READ]
Here is something a bit more simple:
storedword = input("Enter your primary word \t")
word3 = input("Enter anagram word \t")
if storedword == word3[::-1]:
print "Is Anagram"
else:
print "Is not anagram"

Categories