Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modification of the list items in the loop (python) [duplicate]

I'm trying to modify items in a list using a for loop, but I get an error (see below). Sample code:

#!/usr/bin/env python # *-* coding: utf8 *-*  data = [] data.append("some") data.append("example") data.append("data") data.append("here")  for item in data:     data[item] = "everything" 

Error:

Traceback (most recent call last):   File "./testy.py", line 11, in <module>     data[item] = "everything" TypeError: list indices must be integers, not str 

Is there any way to solve this problem?

like image 957
Mateusz Jagiełło Avatar asked Jul 04 '10 06:07

Mateusz Jagiełło


People also ask

Can you modify list while iterating Python?

The general rule of thumb is that you don't modify a collection/array/list while iterating over it. Use a secondary list to store the items you want to act upon and execute that logic in a loop after your initial loop.

Can we modify list while iterating?

Because you iterate over a copy of the list, you can modify the original list without damaging the iterator.

Can you modify for loops?

You can modify the loop variable in a for loop, the problem is that for loops in Python are not like "old-style" for loops in e.g. Java, but more like "new-style" for-each loops.


2 Answers

Try this instead:

for i in xrange(len(data)):     data[i] = "everything" 

The basic problem you're having is that when you write data[i], with data being a list, the i needs to be an integer, a numerical index into the list. But in the loop

for item in data 

item is the actual thing that's in the list, i.e. a string, not the numerical index of the thing. xrange is an iterator that produces numbers instead of the values in the list, so you can use that.

An alternative would be

for i, _ in enumerate(data):     data[i] = "everything" 

The enumerate function gives you an iterator over tuples of the form (index, item), so all you need to do is take the index and forget about the item. I'm not sure that one way or the other (enumerate or xrange) will be significantly faster or better, since I think lists store their length in a variable so it can be quickly accessed without counting through the list elements.

However, if you need the old list value to compute the new list value, the enumerate way will probably be slightly faster because you avoid making Python look up the element in the list:

for i, item in enumerate(data):     data[i] = func(item) 

This sort of thing is better expressed as a list comprehension, though:

data = [func(item) for item in data] 

When you do this, Python will go through each item in data, apply the function to it, and construct a new list from the results automatically, so you don't need to worry about putting the result of func(item) in the right place in the list. Your original example could actually be expressed as

data = ["everything" for item in data] 
like image 199
David Z Avatar answered Oct 03 '22 23:10

David Z


List items are accessed by integer index, i. e. in your example data[1] == 'example'. This is why Python complains when you're using a string as a lookup.

If you want to find an element in a list by its value, you can use data.index("value"):

data[data.index("some")] = "something else" 

But if you just want to loop over them, use enumerate() as David suggested.

like image 34
Tim Pietzcker Avatar answered Oct 03 '22 23:10

Tim Pietzcker