简体   繁体   中英

Removing tuples from a list

I'm trying to remove a tuple from a list. If the first element in the list equals "-NONE-" I want to remove the whole tuple. I keep getting an error when I try different things. Here's what I have:

def filter(sent):
    for tuple in sent:
        if tuple[1] == "-NONE-":
            sent.remove(sent.index(tuple))

I'm using this test to call the method:

filter([('uh', 'UH'), ('i', 'PRP'), ('think', 'VBP'), (',', ','), ('*0*', '-NONE-'), ('it', 'PRP'), ("'s", 'BES'), ('because', 'IN'), ('i', 'PRP'), ('get', 'VBP'), ('*', '-NONE-'), ('to', 'TO'), ('be', 'VB'), ('something', 'NN'), ('that', 'WDT'), ('i', 'PRP'), ("'m", 'VBP'), ('not', 'RB'), ('*T*', '-NONE-'), ('.', '.')])

but I keep getting this error:

Traceback (most recent call last):
File "<pyshell#273>", line 1, in <module>
filter([('uh', 'UH'), ('i', 'PRP'), ('think', 'VBP'), (',', ','), ('*0*', '-NONE-'), ('it', 'PRP'), ("'s", 'BES'), ('because', 'IN'), ('i', 'PRP'), ('get', 'VBP'), ('*', '-NONE-'), ('to', 'TO'), ('be', 'VB'), ('something', 'NN'), ('that', 'WDT'), ('i', 'PRP'), ("'m", 'VBP'), ('not', 'RB'), ('*T*', '-NONE-'), ('.', '.')])
File "<pyshell#272>", line 4, in filter
  sent.remove(sent.index(tuple))
ValueError: list.remove(x): x not in list

The remove method takes an object to remove from the list, not an index. You could either use del , which does take an index, or pass the tuple to remove directly:

def filter(sent):
    for tuple in sent:
        if tuple[1] == "-NONE-":
            # del sent[sent.index(tuple)]
            sent.remove(tuple)

However, this still won't work. You're modifying the list while iterating over it, which will screw up your position in the iteration. Also, both index and remove are slow, and it's a bad idea to name a function filter , hiding the built-in filter function. It would most likely be better to create a new, filtered list with a list comprehension:

def filtered(sent):
    return [item for item in sent if item[1] != "-NONE-"]

All you need to do is

sent.remove(tuple)

If you absolutely want to find the index you need to use pop instead, like so:

sent.pop(sent.index(tuple))

Remove finds the object in the list and then removes it (but only if it is there). Pop works with indices


As user2357112 noted, you shouldn't be removing items from the same list you iterate over. This will undoubtedly cause you headaches. Their answer is the better one.

Your immediate error is that list.remove expects an item as its argument, not an index. That is, you'd want to use sent.remove(tuple) rather than sent.remove(sent.index(tuple)) . Or alternatively, use del , which does delete by index ( del sent[sent.index(tuple)] ). However, with either of those fixes you're still going to have issues with your algorithm.

The reason is that you're iterating over the list at the same time you're removing items from it. Lists iterate by using indexes internally, so when you remove one item, all the later ones move up one space and the next item after the one you've removed will be skipped by the iteration.

A better approach is usually to use a list comprehension to filter your list:

def filter(sent):
    return [tuple for tuple in sent if tuple[1] != "-NONE-"]

Note that this returns a new list, rather than modifying the original list in place. If you want to modify things in place, you can do that, but you'll need to iterate over the list in reverse so that the indexes of the values you haven't checked yet won't get changed. Here's one possible way to do that, though they're all a bit ugly:

def filter(sent):
    for i, val in enumerate(reversed(sent), 1): # iterate in reverse order
        if val[1] == "-NONE-":
            del sent[-i] # del operator removes items by index

Instead of defining your own filter function, use the built-in function:

z = [('uh', 'UH'), ('i', 'PRP'), ('think', 'VBP'), (',', ','), ('*0*', '-NONE-'), ('it', 'PRP'), ("'s", 'BES'), ('because', 'IN'), ('i', 'PRP'), ('get', 'VBP'), ('*', '-NONE-'), ('to', 'TO'), ('be', 'VB'), ('something', 'NN'), ('that', 'WDT'), ('i', 'PRP'), ("'m", 'VBP'), ('not', 'RB'), ('*T*', '-NONE-'), ('.', '.')]
z_filtered = filter(lambda item: item[1] != '-NONE-', z)

Or use itertools.ifilter():

import itertools as it
filtered = list(it.ifilter(lambda item: item[1] != '-NONE-', z))

Those are both a bit slower than @Blckknght's or @user2357112's list comprehension. This is competitive though:

def f(z):
    for item in z:
        if item[1] != '-NONE-':
            yield item
filtered = list(f(z))

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