This question already has an answer here:
safe usage of remove method in python
(1 answer)
Closed 4 years ago.
import itertools
Numb = 'abxxxc'
L=list(itertools.permutations(list(Numb)))
L=[''.join(str(i) for i in x) for x in L]
K=L[::]
for i in range(len(L)):
if K[i][-1] == 'x':
del K[i]
print(L)
I have a code like this and when I run this it gives me an error.
if K[i][-1]=='x':
IndexError: list index out of range
and I have no idea why. I tried everything but still it gives me error.Can someone please help me to see where is my error ?
Edit:
L=list(itertools.permutations(list(Numb)))
L=[''.join(str(i) for i in x) for x in L]
for i in range(len(L)):
if L[i][5] == 'x':
del L[i]
print(L)
L is 720 elements long.
for i in range(len(L)) corresponds to for i in range(720)
You delete elements from K, so at a certain moment, K is 432 elements long, and i is 432
(you are trying to take the 433nd element of a 432-long list)
Perhaps this should do the job ?
import itertools
Numb = 'abxxxc'
L=list(itertools.permutations(list(Numb)))
L=[''.join(str(i) for i in x) for x in L]
K = [elt for elt in L if elt[-1] != 'x']
print(K)
You should usually try to avoid using del. It is better to construct a new list containing the elements you need.
It's a bad practice to delete elements while iterating a list.
A better version will be:
K = [element for element in K if element[-1] != 'x']
You are erasing element from the list while you're iterating it, so there will be a point where you refear to an index that does not exist anymore.
You can solve this problem with list comprehension:
mylist = [K[x] for x in range(len(L)) if (K[x][-1] != 'x')]
Related
This question already has answers here:
python : list index out of range error while iteratively popping elements
(12 answers)
Closed 2 years ago.
Im getting an error for list index being out of range. Sorry if this is a stupid question.
def filter_list(l):
for x in range(0, len(l)):
if type(l[x]) is str:
del l[x]
return l
When you use del to delete the item in the list, the list actually shortens and it seems like that is what is causing the problem.
If you would like to filter lists, you could use list comprehensions like so:
def filter(l):
return [item for item in l if type(item) is not str]
Usually, when looping over lists, it is good practice not to delete or insert new items.
Hope this helped
You should not definitely change a list while iterating over it. It is very bad practise... it can lead to a whole lot of errors for you. Either you should create a copy of use something else, as list comprehension:
def filter_list(l):
return [x for x in l if type(x) is not str]
print(filter_list([1, 4, 5, 's', 'demo'])) # Prints [1, 4, 5]
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 2 years ago.
Can someone explain to me why this code removes only one element from the list not each as I would expect?
So I have a list, let's say it is: [1,2,'a','b']
I want to remove each string from the list.
def filter_list(l):
for i in l:
if type(i) == str:
l.remove(i)
filter_list([1,2,'a','b'])
So after this I receive = [1,2,'b'] which is confusing.
Check this out:
l = [1,2,'a','b']
print([item for item in l if isinstance(item, int)])
I suggest you use isinstance built-in function instead of type. And also it is better to check is an integer in case of your list has an item that different from string or integer.
If you want to remove it, you can simply assign the new list on the old one.
l = [1,2,'a','b']
l = [item for item in l if isinstance(item, int)]
print(l)
Why you cannot over loop:
Let me explain.
def filter_list(l):
for index, i in enumerate(l):
if type(i) == str:
l.remove(i)
return l
filter_list([1,2,'a','b'])
1st iteration the index of for loop is 0:
i becomes 1, and no need to remove it.
2nd iteration the index of for loop is 1:
i becomes 2, and no need to remove it.
3rd iteration the index of for loop is 2:
i becomes 'a', and need to remove it.
At this point, we simply removed the 'a'. The length of the list changed.
It decreased by 1. The new list became [1, 2, 'b'] because we removed 'a'.
4th iteration the index of for loop is 3:
Since we removed the variable in the previous iteration, the list no longer has the index of 3. The loop will raise StopIteration error(IndexError), and breaks.
That is why we cannot do this properly.
Lambda Function:
[*filter(lambda x: isinstance(x, int), l)]
Data:
l = [1,2,'a','b']
This question already has answers here:
Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add (append) elements to a list?
(9 answers)
Closed 2 years ago.
When I am trying to initialize an empty list in Python 3.7.3 using the following code snippet, it is throwing an index error. Can anyone please explain the cause and recommend some corrective action?
newlist = list()
x = 2
for i in range(0, 5):
newlist[i] = x*2
print(newlist)
O/P: IndexError: list assignment index out of range
This is not related to python version. The newlist is empty and you cannot access empty list which gives the error.
If you look step by step:
newlist = list()
Viewing newlist at this point gives as:
print(newlist)
will give: []
In the for loop i starts from 0 so, first iteration of the loop will cause:
newlist[0] = x*2
which gives IndexError since list is empty you cannot access by index. So what you probably need is .append to add to the newlist as following:
newlist = list()
x = 2
for i in range(0, 5):
newlist.append(x*2) # <-- Append to newlist
print(newlist)
You can only access elements at indexes, that exist.
So you have to append elements first:
newlist = list()
x = 2
for i in range(0, 5):
newlist.append(x*2)
print(newlist)
Your code is trying to "inject" the value of x*2 into a list at 4 index locations, however, your list is already empty.
So, how can you access those indices to "inject" values into which do not exist in the first place?
You can rectify your code by using append() method which will keep on adding the value of x*2 to the end of the list on each iteration, thereby, creating the required indices in the process:
newlist = list()
x = 2
for i in range(0, 5):
newlist.append(x*2)
print(newlist)
Hope this clarifies.
A pythonic way to do what you want
x=2
newlist = [x*2 for x in range(0,5)]
print(newlist)
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 6 years ago.
I have a list such as this:
l = ['(7 - 3)', '7 - 6', '(a + 13)']
I want to remove any expression that does NOT contain the letter "a" therefore the only expression that would be left is ['(a+13)'].
So far I have tried this:
for i in range(len(l)):
if "a" not in l[i]:
l.pop(i)
else:
print(l[i])
However I am getting a list index out of range error, and do not know how to fix this.
Could anyone help resolve this?
l.pop() removes elements from the list, so your list is getting smaller but you are not adjusting your iteration.
>>> x = [1,2,3]
>>> x.pop(0)
1
>>> x
[2, 3]
>>> x.pop(1)
3
>>> x
[2]
>>> x.pop(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
I would suggest you take a different approach. You could iterate over the elements of the list directly and print the ones that have "a" in them.
for i in l:
if "a" in i:
print(i)
If you need the list to have only the elements that have "a" in them at the end of your iteration, perhaps you would like to add those items to a new list.
things_with_a_in_them = []
for i in l:
if "a" in i:
things_with_a_in_them.append(i)
print(i)
If you want it to be terser...
things_with_a_in_them = [i for i in l if "a" in i]
map(print, things_with_a_in_them)
Have fun playing around with different approaches.
Never structurally manipulate a list while iterating over it! Use a conditional comprehension
l = [x for x in l if 'a' in x]
or filter:
l = filter(lambda x: 'a' in x, l)
# in Python3, you will have to convert the filter object to a list
# l = list(filter(lambda x: 'a' in x, l))
The problem is len(l) returns 3, but as soon as you pop an item, your list becomes shorter. Easiest thing to do (assuming your list isn't prohibitively giant) would be to just write a new list:
l_new = [i for i in l if "a" in i]
If you don't want to create a new list, and keep your logic with the pop, you would have to check for the len(l) everytime, you can do that by:
l = ['(7 - 3)', '7 - 6', '(a + 13)']
i = 0
while i < len(l):
if "a" not in l[i]:
l.pop(i)
else:
print(l[i])
i += 1
But as others have aswered, it would be better to create a new list with list comprehension
This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 7 years ago.
I have a list in the given format:
[['John', 'Smith'], ['Linus', 'Torvalds'], ['Bart', 'Simpson']]
There are some elements like this in the list ['Linus Torvalds', ''] and I want to remove those. So why doesn't the following code remove them?
for i in people:
if(i[0] == '' or i[1] == ''):
print people.pop(people.index(i))
You are changing the list while iterating over it and this is the source of your problems. An approach that works is
people[:] = [p for p in people if p[0] != '' and p[1] != '']
this way a new temporary list containing only the elements you want is built and then assigned to the original list object when the operation is complete.
Or even people[:] = [p for p in people if all(p)] if you want to resize the list "in place".
You're modifying the list's length while iterating over it. That causes you to skip values. When you pop one item off the list, here's what happens (stealing from this answer):
[1, 2, 3, 4, 5, 6...]
^
That's the state of the list initially; now say 1 is removed and the loop goes to the second item in the list:
[2, 3, 4, 5, 6...]
^
And so on.
It's a bad idea to remove things from a list as you iterate over it. So, try one of these instead (Also, I think your condition is not what you want it to be - I've fixed it):
L = [['John', 'Smith'], ['Linus', 'Torvalds'], ['Bart', 'Simpson']]
delete_these = []
for index, i in enumerate(L):
if not i[-1].strip():
delete_these.append(i)
for i in delete_these:
L.pop(i)
delete_these = map(lambda x: x-1, delete_these)
OR
L = [i for i in L if i[-1].strip()]
OR
answer = []
for i in L:
if i[-1].strip():
answer.append(i)
OR
i = 0
while i < len(L):
if not L[i][-1].strip():
L.pop(i)
else:
i += 1
Hope this helps