简体   繁体   中英

“list index out of range” - Python

I was trying to write a piece of program that will remove any repeating items in the list, but I get a list index out of range

Here's the code:

a_list = [1, 4, 3, 2, 3]

def repeating(any_list):
    list_item, comparable = any_list, any_list
    for x in any_list:
        list_item[x]
        comparable[x]
        if list_item == comparable:
            any_list.remove(x)

    print(any_list)

repeating(a_list)

So my question is, what's wrong?

The easiest way to solve your issue is to convert the list to a set and then, back to a list...

def repeating(any_list):
    print list(set(any_list))

You're probably having an issue, because you're modifying the list (removing), while iterating over it.

Your code does not do what you think it does.

First you are creating additional references to the same list here:

list_item, comparable = any_list, any_list

list_item and comparable are just additional names to access the same list object.

You then loop over the values contained in any_list :

for x in any_list:

This assigns first 1 , then 4 , then 3 , then 2 , then 3 again to x .

Next, use those values as indexes into the other two references to the list, but ignore the result of those expressions:

list_item[x]
comparable[x]

This doesn't do anything, other than test if those indexes exist.

The following line then is always true :

if list_item == comparable:

because the two variables reference the same list object.

Because that is always true, the following line is always executed:

any_list.remove(x)

This removes the first x from the list, making the list shorter , while still iterating. This causes the for loop to skip items as it'll move the pointer to the next element. See Loop "Forgets" to Remove Some Items for why that is.

All in all, you end up with 4, then 3 items in the list, so list_item[3] then fails and throws the exception.

The proper way to remove duplicates is to use a set object :

def repeating(any_list):
    return list(set(any_list))

because a set can only hold unique items. It'll alter the order however. If the order is important, you can use a collections.OrderedDict() object :

def repeating(any_list):
    return list(OrderedDict.fromkeys(any_list))

Like a set , a dictionary can only hold unique keys, but an OrderedDict actually also keeps track of the order of insertion; the dict.fromkeys() method gives each element in any_list a value of None unless the element was already there. Turning that back in to a list gives you the unique elements in a first-come, first serve order:

>>> from collections import OrderedDict
>>> a_list = [1, 4, 3, 2, 3]
>>> list(set(a_list))
[1, 2, 3, 4]
>>> list(OrderedDict.fromkeys(a_list))
[1, 4, 3, 2]

See How do you remove duplicates from a list in whilst preserving order? for more options still.

If you want to remove duplicates in a list but don't care about the elements formatting then you can

def removeDuplicate(numlist):
    return list(set(numlist))

If you want to preserve the order then

def removeDuplicate(numlist):
    return sorted(list(set(numlist)), key=numlist.index)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM