Removing tuples from a list

后端 未结 4 1594
时光说笑
时光说笑 2021-01-29 04:38

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 th

相关标签:
4条回答
  • 2021-01-29 04:43

    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-"]
    
    0 讨论(0)
  • 2021-01-29 04:44

    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.

    0 讨论(0)
  • 2021-01-29 04:46

    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))
    
    0 讨论(0)
  • 2021-01-29 04:49

    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
    
    0 讨论(0)
提交回复
热议问题