Igor234
Igor234

Reputation: 389

two ways of looping over list - difference

I have to reverse every word in a list which length is greater that 4. So I tried:

for word in words:
    if len(word) >= 5:
        word = word[::-1]

and it didn't work. But this:

 for i in range(len(words)):
        if len(words[i]) >= 5:
            words[i] = words[i][::-1]

works fine. What's the diference?

Upvotes: 5

Views: 229

Answers (4)

ViperStream
ViperStream

Reputation: 3

The reason why is because when you do the first one, you are only modifying the word variable, you aren't modifying the words list. But when you are using the second example, you are modifying it because you are using words[i] = words[i][::-1]. In this example, you are modifying the words list because the words[i] is the modifier; you are setting the element of the list into something.

Upvotes: 0

Ahmed Fasih
Ahmed Fasih

Reputation: 6927

To understand what's going on here, compare what happens in a similar example, where I want to set any numbers bigger than 20 to -1:

numbers = [1, 10, 30, 40, 50]
for number in numbers:
    if number > 20:
        number = -1
print(numbers) # same as before!

Why does this not set the last three numbers to -1? Because number here is a value—it's location in memory is totally unrelated to the contents of the numbers array. word in your example is exactly the same.

Inside your loop, word is bound to a new piece of memory whose contents happen to be the same as the current entry of the words array. By the time word is defined in your first snippet, you have lost any way to manipulate the array location it came from. By iterating over the indexes like in your second snippet, you keep a back door into the array.

These two references,

might help understand the following tricky business: instead of a list of strings, what happens if we have a list of lists?

listOfLists = [[1], [2, 3], [9, 10, 11], [40, 50, 60, 70]]
for l in listOfLists:
    if len(l) >= 3:
        l[:] = l[::-1] # note that `[:]`!!!
print(listOfLists)

This actually will reverse any sub-list that has more than 2 elements. Can you understand why? If so, take this gold star: 🌟!

Upvotes: 0

Anton vBR
Anton vBR

Reputation: 18916

When you iterate through a list Python creates references (with same ID) to your variable. However these are not editable in place. Check this for instance: Can't modify list elements in a loop Python

Consider this example which hopefully can help you out:

words = ['abcdef','abc']

for ind,i in enumerate(words):
    print('Loop {}'.format(ind))
    i = i[::-1]
    print('words equal {}'.format(words))
    words[ind] = words[ind][::-1] 
    print('words equal {}'.format(words))    
    print()

Returns:

Loop 0
words equal ['abcdef', 'abc']   # <--- after changing i (nothing changed)
words equal ['fedcba', 'abc']   # <--- after changing words[ind]

Loop 1
words equal ['fedcba', 'abc']   # <--- after changing i (nothing changed)
words equal ['fedcba', 'cba']   # <--- after changing words[ind]

in your case

The most simple solution would be to use a list comprehension. Consider this:

rWords = [word[::-1] if len(word) >=5 else word for word in words]

Upvotes: 1

hossein
hossein

Reputation: 313

    word = word[::-1]

word is not referenced to the words[i]. You can do this with functional programming.

new_words = list(word[::-1] if len(word) >= 5 else word for word in words)

Upvotes: 0

Related Questions