简体   繁体   English

从列表中删除元素和n个后续元素

[英]Remove element, and n following elements from list

I want to remove all elements from a list I want to iterate over a list, skipping elements that match some test, and a certain number of elements after that match. 我想从列表中删除所有 要迭代的元素,跳过与某些测试匹配的元素,并在匹配之后跳过一定数量的元素。 eg. 例如。

# skip 'foo' and 2 subsequent values

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

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

Is there a more elegant method to achieve this than iterating using a counter building a new list and skipping forwards n iteratations when the match is found? 有比使用建立新列表的计数器进行迭代并在找到匹配项时跳过n迭代进行迭代的更优雅的方法吗? ie. 即。

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]

Hmm, how about a generator? 嗯,发电机怎么样?

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))

Just slice-delete. 只是切片删除。

>>> 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]

And now, a coroutine solution. 现在,有了协程解决方案。

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)]

Write a simple function to work with del slices of the list: 编写一个简单的函数来处理列表的del slice:

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

output: 输出:

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

and same but not changing the variable: 相同但不更改变量:

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

output: 输出:

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

Depends on your definition of elegant, and whether you want to do what your question title says (remove from a list ie not making a new list). 取决于您对雅致的定义,以及您是否要执行题名所说的(从列表中删除,即不创建新列表)。

The first function below safely mutates the existing list by iterating backwards and deleting the unwanted stuff. 下面的第一个函数通过向后迭代并删除不需要的内容来安全地更改现有列表。 The second function iterates forwards using list.index until the marker is not found (IOW what Ignacio's answer suggested). 第二个函数使用list.index向前迭代,直到找不到标记为止(IOW Ignacio的答案建议)。 The third function is a modified version of the first, assuming that the question is taken literally eg ['foo', 'foo', 1, 2] is reduced to [] , not [2] . 第三个函数是第一个函数的修改版本,假设问题是从字面上理解的,例如['foo', 'foo', 1, 2]简化为[] ,而不是[2]

Code: 码:

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)

Output: 输出:

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]

A good solution using a defined function: 使用定义的函数的良好解决方案:

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

And using the function with your data: 并将函数与数据一起使用:

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

Good thing about this code is that it won't fail even if you want to remove out-of-range elements, for example: 这段代码的好处是,即使您要删除超出范围的元素,它也不会失败,例如:

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

Functional version: 功能版本:

It's a bit messy, though. 不过,这有点混乱。

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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