(Python) List index out of range - iteration [duplicate] - python

This question already has answers here:
python : list index out of range error while iteratively popping elements
(12 answers)
How to remove items from a list while iterating?
(25 answers)
Closed 6 years ago.
for i in range(len(lst)):
if lst[i][0]==1 or lst[i][1]==1:
lst.remove(lst[i])
return lst
This gives "IndexError: list index out of range" Why is this happening?

You're modifying the list you're iterating over. If you do that, the size of the list shrinks, so eventually lst[i] will point beyond the list's boundaries.
>>> lst = [1,2,3]
>>> lst[2]
3
>>> lst.remove(1)
>>> lst[1]
3
>>> lst[2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
It's safer to construct a new list:
return [item for item in lst if item[0]!=1 and item[1]!=1]

You shouldn't remove items from the list as you iterate over it; that changes the indices of all subsequent items, hence the IndexError. You could try a simple list comprehension:
lst = [item for item in lst if (item[0] != 1 and item[1] != 1)]

Generally it means that you are providing an index for which a list element does not exist.
E.g, if your list was [12, 32, 50, 71], and you asked for the element at index 10, you would be well out of bounds and receive an error, as only elements 0 through 3 exist.

The problem is that you remove items in the list which reduces its size. What you have to do is make an array with the indexes you want to remove and remove them backwards.
Another way would be to create a temporary list that you would add the elements you don't want to delete and then overwrite your initial list with the list containing all the elements you want to keep.

By process of deduction I have concluded that your lst looks something like this:
lst = [ ...[val1, val2], [val1, val2], [val1, val2]... ]
I think what happened here is you confused your 'for i in range', with a 'for i in' (I have done this many times also.)
The line where your error is occurring is:
lst.remove(lst[i])
You can correct this by simply changing your code like so:
for i in lst:
if i[0] ==1 or i[1] ==1:
lst.remove(lst[i])
return lst
The way your code was structured before list[i] didn't make any sense, your i was a number greater than the number of two-value-items in lst.
=D

Related

I want to remove duplicates from the list using for loop.I am getting index out of bound error here:if lst[i]==lst[j]:

I have declared a list and sorted it.While iterating the second for loop I am getting :index out
of range error.
lst=[]
for i in range(5):
a=int(input())
lst.append(a)
lst.sort()
print(lst)
for i in range(0,len(lst)):
j=i+1
for j in range(len(lst)):
if lst[i]==lst[j]:
print("hii")
lst.pop(j)
print(lst)
As you remove elements from lst it's length change so your iteration breaks when it tries to access an empty index: "Index out of bound"
If you want to keep your structure you could catch that and exit the loop using a try/catch on IndexError but it's really ugly.
A more pythonic solution is to simply cast your list as a set then back to list. This works because sets remove all of their duplicate elements:
>>> list(set([1, 1, 2, 2, 3, 4,]))
[1, 2, 3, 4]
You shouldn't change the length of your list while iterating over it, I am assuming you want to delete all duplicates in your original list. You can use cast the list to a set with
set(lst)
before you sort or after you sort.
You're getting this error thrown as you are changing the length of a list whist iterating over it.
A simpler approach to removing all duplicates from a list would be to create a set based on the list which is then converted back to a list - this should be done before you sort your list as a set (by definition) does not preserve ordering of elements.
Using your example:
lst = []
for i in range(5):
a=int(input())
lst.append(a)
lst = list(set(lst)) # Remove duplicates from list
lst.sort() # Sort list

delete list element by index while iterating using python [duplicate]

This question already has answers here:
Removing from a list while iterating over it [duplicate]
(5 answers)
Closed 6 years ago.
In a list, I have duplicate elements that I want to remove.
The following code doesn't work:
Note:
temp containts the list of indexes of elements that I want to remove.
x is my list.
temp = self.list_duplicates(x)
for index in tmp:
del x[index]
Build a new list with a comprehension:
x = [element for (i,element) in enumerate(x) if i not in temp]
If you want to remove only duplicates, i.e. leaving one copy of the original, there is a better way to do that:
from collections import OrderedDict
x = list(OrderedDict.fromkeys(x))
x.pop(index) will remove the item at index. However, x = [x[i] for i in range(len(x)) if x[i] not in x[:i]] will remove the duplicates more quickly.
No one addressed the first part of the question. So, for removing duplicate items its wise to use set(), it removes the duplicate items and returns a arbitrary list of unique items.
lst = [1,1,2,3,4,4]
new_lst = list(set(lst))
print(lst)
It will return unique list of elements in an arbitrary manner Eg : [1,4,2,3]
You can filter the list with the following:
Edit: Works now for list of indices
x = list(filter(lambda item: x.index(item) not in temp, x))

while loop - IndexError: list index out of range

Maybe it's too simple and I just didn't see my mistake.
while list_a[y] in list_a != list_a[-1]:
print(y);y=y+1
returns IndexError: list index out of range
list_a looks like:
['00001', '00001', '00002', '00009', '0000G', '0000K', '0000K', '0000U', '0000U', '00013', '0001B', '0001D', '0001D', '0001L', '0001L', '0001N', '0001Q', '0001Q', '0001R', '0001U']
and my aim in the end is to delete some items from the list while iterating (that's why I want to use a while loop instead of for y in range(len(list_a))).
Think what you were trying for was:
while list_a[y] != list_a[-1]:
...
i.e. "while we're looking at the item that isn't equal to the last in the list". However, there will still be issues; what if items appear elsewhere in the list that are equal to the last item?
The general way to do this is to use a list comprehension to build a new list from the appropriate items in the old list:
list_b = [item for item in list_a if some_test(item)]

how to convert two lists into a dictionary (one list is the keys and the other is the values)? [duplicate]

This question already has answers here:
How can I make a dictionary (dict) from separate lists of keys and values?
(21 answers)
Closed 6 years ago.
This is code in IDLE2 in python, and error.
I need to include each "data" element as key and value "otro", in an orderly manner. Well "data" and "otro" it's list with 38 string's, as for "dik" it's an dictionary.
>>> for i in range(len(otro)+1):
dik[dato[i]] = otro[i]
Traceback (most recent call last):
File "<pyshell#206>", line 2, in <module>
dik[dato[i]] = otro[i]
IndexError: list index out of range
>>>
this problem is range(0, 38)
output -> (0, 1,2,3 ... 37) and it is all messy
I think something like:
dik = dict(zip(dato,otro))
is a little cleaner...
If dik already exists and you're just updating it:
dik.update(zip(dato,otro))
If you don't know about zip, you should invest a little time learning it. It's super useful.
a = [ 1 , 2 , 3 , 4 ]
b = ['a','b','c','d']
zip(a,b) #=> [(1,'a'),(2,'b'),(3,'c'),(4,'d')] #(This is actually a zip-object on python 3.x)
zip can also take more arguments (zip(a,b,c)) for example will give you a list of 3-tuples, but that's not terribly important for the discussion here.
This happens to be exactly one of the things that the dict "constructor" (type) likes to initialize a set of key-value pairs. The first element in each tuple is the key and the second element is the value.
The error comes from this: range(len(otro)+1). When you use range, the upper value isn't actually iterated, so when you say range(5) for instance, your iteration goes 0, 1, 2, 3, 4, where position 5 is the element 4. If we then took that list elements and said for i in range(len(nums)+1): print nums[i], the final i would be len(nums) + 1 = 6, which as you can see would cause an error.
The more 'Pythonic' way to iterate over something is to not use the len of the list - you iterate over the list itself, pulling out the index if necessary by using enumerate:
In [1]: my_list = ['one', 'two', 'three']
In [2]: for index, item in enumerate(my_list):
...: print index, item
...:
...:
0 one
1 two
2 three
Applying this to your case, you can then say:
>>> for index, item in enumerate(otro):
... dik[dato[index]] = item
However keeping with the Pythonicity theme, #mgilson's zip is the better version of this construct.

Removing items from a list in a loop [duplicate]

This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 7 years ago.
For quite a bit of time now I have been trying to figure out a way to loop through a list and remove the current item that I'm at. I can't seem to get this working as I would like it to. It loops just 1 time through, but I wanted it to loop 2 times. When I remove the removal line - it loops 2 times.
a = [0, 1]
for i in a:
z = a
print z.remove(i)
The output:
[1]
The output that I was expecting:
[1]
[0]
You're changing the list while iterating over it -- z = a doesn't make a copy, it just points z at the same place a points.
Try
for i in a[:]: # slicing a list makes a copy
print i # remove doesn't return the item so print it here
a.remove(i) # remove the item from the original list
or
while a: # while the list is not empty
print a.pop(0) # remove the first item from the list
If you don't need an explicit loop, you can remove items that match a condition with a list comprehension:
a = [i for i in a if i] # remove all items that evaluate to false
a = [i for i in a if condition(i)] # remove items where the condition is False
It is bad practice modify a list while you're looping through it†. Create a copy of the list:
oldlist = ['a', 'b', 'spam', 'c']
newlist = [x for x in oldlist if x != 'spam']
To modify the original list, write the copy back in-place with a slice assignment:
oldlist[:] = [x for x in oldlist if x != 'spam']
† For a gist of why this might be bad practice, consider the implementation details of what goes on with the iterator over the sequence when the sequence changes during iteration. If you've removed the current item, should the iterator point to the next item in the original list or to the next item in the modified list? What if your decision procedure instead removes the previous (or next) item to the current?
The problem is that you're modifying a with remove so the loop exits because the index is now past the end of it.
Don't try to remove multiple items of a list while looping the list. I think it's a general rule you should follow not only in python but also in other programming languages as well.
You could add the item to be removed into a separate list. And then remove all objects in that new list from the original list.

Categories