10/15 - "list indices must be integers, not str"


#1

So I have been getting this error. I know that means that I am doing an illegal operation (trying to maybe loop through strings?), but I thought strings were iterable in a list!!

def censor(text, word):
  wordlist = text.split(" ")
  for i in wordlist:
    if i == word:
      i = len(wordlist[i]) * "*"
      
  " ".join(wordlist)
  return wordlist

What I have here is:
Line 1: a piece of text and a word as inputs x and y.
Line 2: a variable, wordlist. It splits the text into chunks of words and forms a list with strings as indices. Right?
Line 3: For “every index” (in this case, words) in this list I just made…
Line 4: if this word matches the input y (from above)
Line 5: change the word to *'s multiplied by the length of i (still the string).

Where does my logic fall apart?

Edit: I changed

      i = len(wordlist[i]) * "*"

to

      i = len(i) * "*"

I feel like I am getting close. It’s not censoring my text. Back to the drawing board… but I feel like I am on the right track.


#2

What’s i and why is it named i?


#3

i is a list of words, like… each word.

I named it i because I started really confusing myself when I named it “words” (since it’s close to “word”)

Unless you were asking me because I have something wrong there?


#4

Is it?

So if you

print type(i)

you get

list

?


#5

Either way, i is hardly an appropriate name for a list

i is used a whole lot in C-like languages because they need a name for “iteration” or “index” which they do all the time with their

size_t length = strlen(mystring);
for (int i = 0; i < length; i++) {
    char c = mystring[i];
    ...
}

Which we luckily don’t do…

for c in mystring:
    ...

Though sometimes we might want exactly that:

for i in range(100):
    print i  # 0 1 2 3 4 5 ... 98 99

#6

Oh.

But you’re not treating i like a word

You’re treating it like you named it, like an integer

list indices must be integers, not str

You’re using a string where you have an integer, which you do catch on to with

But that’s adding to the confusion because now it changed meaning, it’s something completely different


#7

The solution is to go for simple and obvious:

def censor(text, badword):
    for word in text.split():
        # do something

You have two words in your context, how do they differ? One is bad, so now you have two different names, and the names are accurate and meaningful.

When I say obvious I mean it’s obvious when it’s read. It’s not necessarily obvious how to make it obvious. That is hard, but it makes everything else easier.


#8

Okay, I’ll try not to use i if I’m able to make it more clear.

Using your template, I came up with

def censor(text, badword):
    for word in text.split(" "):
      if word == badword:
        word = "*" * len(word)
    " ".join(text)
    return text

The code looks a lot more intuitive (easier to read). But I know I am missing a key part…

How do I replace a string in a list?

for word in text.split(" "):

This turned text into a list of strings right?

Should I implement a counter to keep track of where the string is and then use text[#] to put asterisks in where badword occurs? Or should I be thinking more simple?


#9

It would be reasonable to modify the list because, unlike in anti-vowel, there’s no need to resize the list, just replace a single value.

I generally prefer to create a new value based on the old one. This isn’t always the right thing to do, but when processing the whole thing anyway there’s not much cost to it.

Either is fine.


#10

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.