Erica
Erica

Reputation: 61

How to alternate case in a provided string using a for loop

I want to create a for loop that will alternate upper and lowercase letters in a provided string (given as user input). My general idea is to make a for loop starting at 0 and ending at the length of the string, with a step size of 2. This is what I have so far (x is the string variable).

for a in range (0,len(x),2):
    x=x[0:a] + x[a].upper + x[a+1::]
    print("Alternate Lowercase Letters:", a)

When I use this, I get an error message that says

"TypeError: must be str, not builtin_function_or_method"

Any suggestions?

Upvotes: 2

Views: 948

Answers (3)

PM 2Ring
PM 2Ring

Reputation: 55469

As mentioned earlier, the cause of that error is that you have x[a].upper instead of x[a].upper(). So Python thinks you want to concatenate that method with the x[0:a] and x[a+1::] strings, and that doesn't make sense.

However, there are better ways to do this task. You can use a list comprehension to perform the case-changing and then use the .join method to convert the list contents into a string. Here are two variations.

We can use enumerate to get the character index while we iterate over the characters in the input string. If the index is odd, we make the char lower-case, otherwise we make it upper-case.

def alt_case(s):
    return ''.join([u.lower() if i % 2 else u.upper() for i, u in enumerate(s)])

Alternatively, we can use slicing to separate the odd & even chars, and then use zip to put them back together after performing the case transformations.

def alt_case(s):
    hi = s[::2].upper()
    lo = s[1::2].lower()
    return ''.join([u+v for u, v in zip(hi, lo)])

Here's code that tests those functions.

s = 'This is a test'
print(alt_case(s))

output

ThIs iS A TeSt

FWIW, here's a cryptic variant of the first version:

def alt_case(s):
    return ''.join([(str.upper, str.lower)[i%2](u) for i, u in enumerate(s)])

Upvotes: 3

Joe Iddon
Joe Iddon

Reputation: 20414

You can use a generater-comprehension with str.join. I believe that this is the most efficient solution:

def alternate(s):
    return ''.join(c.upper() if i & 1 else c.lower() for i, c in enumerate(s))

and a test shows it works:

>>> alternate('testing')
'tEsTiNg'

Upvotes: 2

Sandeep Dcunha
Sandeep Dcunha

Reputation: 134

Your problem, as pault mentioned, is that you use .upper rather than .upper(). The former gives you a function reference, and the latter gives you the return value of the function.

Another thing to consider, if the string x is long, is to cast it to a list and reassign values rather than reconstructing the whole string every iteration. If x is a short string, it doesn't really matter as there will be no perceivable runtime difference, but if it is rather long, there would certainly be a significant difference in runtime since this method is O(x) while your current method is O(x2).

Upvotes: 2

Related Questions