Peibo Zhao
Peibo Zhao

Reputation: 1

How can I upper case the letter with an even index in a string

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

Answers (4)

Jab
Jab

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

ShadowRanger
ShadowRanger

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

Simson
Simson

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

kaya3
kaya3

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

Related Questions