从列表中删除元素和n个以下元素

时间:2012-01-07 22:31:35

标签: python

我想删除列表中的所有元素我想迭代列表,跳过匹配某些测试的元素,以及匹配后的一定数量的元素。的例如

# skip 'foo' and 2 subsequent values

values = [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']

result = [1, 2, 3, 6, 7]

有没有更优雅的方法来实现这一点,而不是使用计数器构建新列表并在找到匹配时跳过转发n迭代?的

values = [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']

result = []

i = 0
while i < len(values):
    if values[i] == 'foo':
        i += 3
    else:
        result.append(values[i])
        i += 1

print result
[1, 2, 3, 6, 7]

7 个答案:

答案 0 :(得分:2)

嗯,发电机怎么样?

def iterskip(iterator, test, n):
    """Iterate skipping values matching test, and n following values"""
    iterator = iter(iterator)
    while 1:
        value = next(iterator)
        if test(value):
            for dummy in range(n):
                next(iterator)
        else:
            yield value

def is_foo(value):
    return value == 'foo'

print list(iterskip(values, is_foo, 2))

答案 1 :(得分:1)

只需切片删除。

>>> values = [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']
>>> values.index('foo')
3
>>> del values[3:3 + 3]
>>> values.index('foo')
5
>>> del values[5:5 + 3]
>>> values.index('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'foo' is not in list
>>> values
[1, 2, 3, 6, 7]

答案 2 :(得分:1)

现在,是一个协程解决方案。

def countdown(val, count):
  curr = 0
  while True:
    now = (yield curr)
    if curr > 0:
      curr -= 1
    if now == val:
      curr = count

values = [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']
c = countdown('foo', 3)
c.next()
print [x for x in values if not c.send(x)]

答案 3 :(得分:1)

编写一个简单的函数来处理列表的del切片:

import copy
def del_sublists(list, value, length, copy_list = False):
    if copy_list:
        list = copy.deepcopy(list)
    while value in list:
        del list[list.index(value):list.index(value) + (length + 1)]
    return list

a = [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']
print del_sublists(a, 'foo', 2)
print a

输出:

[1, 2, 3, 6, 7]
[1, 2, 3, 6, 7]

同样但不改变变量:

a = [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']
print del_sublists(a, 'foo', 2, copy_list = True)
print a

输出:

[1, 2, 3, 6, 7]
[1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']

答案 4 :(得分:1)

取决于您对优雅的定义,以及您是否想要执行您的问题标题所说的内容(从列表中删除,即不创建新列表)。

下面的第一个函数通过向后迭代并删除不需要的东西来安全地改变现有列表。第二个函数使用list.index向前迭代,直到找不到标记(IOW Ignacio的答案建议如何)。第三个功能是第一个功能的修改版本,假设问题是按字面意思进行的,例如: ['foo', 'foo', 1, 2]缩减为[],而不是[2]

代码:

def inplace_munge_1(alist, query, size):
    for i in xrange(len(alist) - 1, -1, -1):
        if alist[i] == query:
            del alist[i:i+size]

def inplace_munge_2(alist, query, size):
    start = 0
    while True:
        try:
            i = alist.index(query, start)
        except ValueError:
            return
        del alist[i:i+size]
        start = i

def inplace_munge_3(alist, query, size):
    marker = len(alist)
    delpos = []
    for i in xrange(len(alist) - 1, -1, -1):
        if alist[i] == query:
            for j in xrange(min(i + size, marker) - 1, i - 1, -1):
                delpos.append(j)
            marker = i
    for j in delpos:
        del alist[j]

funcs = [inplace_munge_1, inplace_munge_2, inplace_munge_3]

tests = [
    [],
    [1],
    ['foo'],
    [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y'],
    ['foo', 'foo', 1, 2, 3],
    ]

fmt = "%-15s: %r"    
for test in tests:
    print
    print fmt % ("Input", test)
    for func in funcs:
        values = test[:]
        func(values, 'foo', 3)
        print fmt % (func.__name__, values)

输出:

Input          : []
inplace_munge_1: []
inplace_munge_2: []
inplace_munge_3: []

Input          : [1]
inplace_munge_1: [1]
inplace_munge_2: [1]
inplace_munge_3: [1]

Input          : ['foo']
inplace_munge_1: []
inplace_munge_2: []
inplace_munge_3: []

Input          : [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']
inplace_munge_1: [1, 2, 3, 6, 7]
inplace_munge_2: [1, 2, 3, 6, 7]
inplace_munge_3: [1, 2, 3, 6, 7]

Input          : ['foo', 'foo', 1, 2, 3]
inplace_munge_1: []
inplace_munge_2: [2, 3]
inplace_munge_3: [3]

答案 5 :(得分:0)

使用定义函数的好解决方案:

def special_remove(my_list, item, start=0):
    try:
        pos = my_list.index(item, start)
        return special_remove(my_list[:pos] + my_list[pos+3:], item, pos)
    except ValueError:
        return my_list

将该功能与您的数据一起使用:

>>> values = [1, 2, 3, 'foo', 'a', 'b', 6, 7, 'foo', 'x', 'y']
>>> special_remove(values, 'foo') [1, 2, 3, 6, 7]

这段代码的好处是,即使你想要删除超出范围的元素,它也不会失败,例如:

>>> values = [1, 'foo']
>>> special_remove(values, 'foo')
[1]

答案 6 :(得分:0)

功能版:

但是,它有点乱。

def unfold(f, x):
    while True:
        try:
            w, x = f(x)
        except TypeError:
            raise StopIteration
        yield w

def test(info):
    values, cur_values, n = info
    length = len(values)

    if n == length:
        return None
    elif n == length-1:
        cur_values = cur_values + [values[n]]
    elif values[n] == "foo" and n < len(values)-2:
        n += 3

    return (cur_values, (values, cur_values + [values[n]], n+1))

values = [1, 2, 3, 'a', 'b', 6, 7, 'foo', 'x', 'y', 2 , 6 , 7, "foo", 4 , 5, 6, 7]
results = list(unfold(test, (values, [], 0)))[-1]
print results

输出:[1,2,3,'a','b',6,7,2,6,7,6,7]