1

My brain cannot comprehend why this isn't working. I'm not very experienced and just trying to practice loops.

I'm trying to create a function that takes a string (currently one word) and capitalizes letters at random. With this code python throws a TypeError: list indices must be integers or slices, not strings

Here's what I have:

import random

list = []

def hippycase(string):
    for letter in string:
        list.append(letter)

    for index in list:
        if random.randint(1,2) == 1:
            list[index] = list[index].upper()
        else:
            list[index] = list[index].lower()
    return list


print(hippycase("pineapple"))

Any ideas or tips? Thanks

EDIT: Since this has been marked as a duplicate as someone thinks is at the following link, I'll try and clear up what is different: Accessing the index in Python 'for' loops I'm not trying to actively seek the index, I'm just practicing for loops which coincidentally goes through the index of the iterable sequentially. I also think if a fellow noob coder is searching this might be more helpful.

Community
  • 1
  • 1
  • Possible duplicate of [Accessing the index in Python 'for' loops](http://stackoverflow.com/questions/522563/accessing-the-index-in-python-for-loops) – Cyclonecode May 15 '17 at 22:25
  • 2
    Python has lots of tools for list processing. You could do this with `list(random.choice((str.upper, str.lower))(c) for c in string)` – tdelaney May 15 '17 at 22:31

2 Answers2

2

The variable "index" that you are using is a letter from the string, because you are iterating over it. To fix this error, use the range() function, which will allow you to access each element in the list by index:

list = []

def hippycase(string):
    for letter in string:
        list.append(letter)

    for index in range(len(list)): #here, we are accessing the elements by index
        if random.randint(1,2) == 1:
            list[index] = list[index].upper()
        else:
            list[index] = list[index].lower()
    return list


print(hippycase("pineapple"))     

Another way is simple list comprehension:

the_string = "pineapple"

print ''.join([i.upper() if random.randint(1, 2) == 1 else i for i in the_string])
Ajax1234
  • 58,711
  • 7
  • 46
  • 83
  • Downvoted as in your example you still have `hippycase` modifying a global `list` variable. What will happen the second time (and third time and ...) that `hippycase` is called? – donkopotamus May 15 '17 at 22:31
  • After Googling the range function I think I understand what's going on. My lack of knowledge will be what gives me an aneurysm. Thanks for your help! – Christian Barry May 15 '17 at 22:36
  • Of course "list" will still store all the variables appended to it from the function, but in the context of this problem and the fact that the OP is specifically calling the function once, I did not fix that in the code. – Ajax1234 May 15 '17 at 22:36
  • I am glad I could help! – Ajax1234 May 15 '17 at 22:36
2

Here's a slightly improved version of your code

def hippycase(string):
    charlist = []
    for char in string:
        if random.randint(1,2) == 1:
            charlist.append(char.upper())
        else:
            charlist.append(char.lower())
    return charlist

Notice that in this version we're looking only at the characters in your string, we don't care about the indices - this helps to reduce confusion.

If I were writing this to actually "hippycase" a string I would probably return "".join(charlist), so the calling function would get back a string (which is what they probably expect)

Also, it is bad practice to overwrite the list reserved word.

Jon Kiparsky
  • 6,854
  • 2
  • 20
  • 37
  • improved version with comprehension's list `[char.upper() if random.randint(1, 2) == 1 else char.lower() for char in string]` – Davichete Nov 27 '19 at 20:06