Reputation: 1
Here is my thought: I want to create new empty string (newst), and add letters in the tested string (st) one by one by testing and upper or lower case the letter depends on the even or odd index.
Below is my code:
def myfunc(st):
newst = ''
for i in st:
if st.index(i) %2 == 0:
newst = newst + i.upper()
else:
newst = newst + i.lower()
return newst
When I test the code:
myfunc('bbAA')
I got: 'BBAA'
Can anyone help me to explain why I got the incorrect result? Thank you
Upvotes: 0
Views: 697
Reputation: 27515
Why not use str.join
and a comprehension:
def myfunc(st):
return ''.join(s.lower() if i % 2 else s.upper() for i , s in enumerate(st))
>>> myfunc('aaBB')
AbAb
Upvotes: 0
Reputation: 155536
st.index(i)
is returning the first index that has that character, so bbAA
finds the index of the first b
for both the first and second b
. It's also highly inefficient, since it needs to perform a linear search for each character.
It's an easy fix though; the enumerate
function will give you the index along with the value for free:
def myfunc(st):
newst = ''
for i, char in enumerate(st):
if i % 2 == 0:
newst += char.upper()
else:
newst += char.lower()
return newst
Note that this does perform a decent amount of moderately expensive math for no reason (you're just alternating after all). One way to avoid it would be to have itertools.cycle
switch back and forth between upper
and lower
for you:
from itertools import cycle
def myfunc(st):
newst = ''
for char, op in zip(st, cycle((str.upper, str.lower))):
newst += op(char)
return newst
Note that while CPython will handle repeated str
appends relatively efficiently, it's only an implementation detail that you can't rely on. A more portable way to do this efficiently might be to use a list
comprehension or generator expression and join
it:
def myfunc(st):
return ''.join([op(char) for char, op in zip(st, cycle((str.upper, str.lower)))])
Upvotes: 1
Reputation: 3559
string.index
returns the first position where the letter you are searching is found, you should use enumerate
to get the letter and its index
def myfunc(st):
newst = ''
for index,alpha in enumerate(st):
if index %2 == 0:
newst = newst + alpha.upper()
else:
newst = newst + alpha.lower()
return newst
print ( myfunc("aaaBBB"))
And output is:
$ python3 hack07.py
AaAbBb
Upvotes: 0
Reputation: 51122
Don't use .index
in a loop to find the index of the current value; it finds the index of the first occurrence of that value, not necessarily the occurrence you're currently looking at. Iterate using enumerate
to get both the index and value together:
def myfunc(st):
newst = ''
for index, char in enumerate(st):
if index % 2 == 0:
newst = newst + char.upper()
else:
newst = newst + char.lower()
return newst
Similar solution using join
and a comprehension:
def myfunc(st):
return ''.join(
char.upper() if index % 2 == 0 else char.lower()
for index, char in enumerate(st)
)
Upvotes: 2