2012-01-07 417 views
0

我想从列表中删除所有元素 我想遍历列表,跳过匹配一些测试的元素以及匹配后的一定数量的元素。 例如。删除元素,并从列表中删除下列元素

# 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 iteratations迭代? 即。

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

请出示你到目前为止的代码。 – 2012-01-07 22:33:50

+0

它应该如何处理'[1,'foo',3,'foo',5,6,7]'? – 2012-01-07 22:42:09

+0

这会返回'[1,5,6,7]'我想。用例假定每次出现'foo'后都会遵循两个我们不关心的值。 – Acorn 2012-01-07 22:45:02

回答

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。几个nits:1.使用'next(iterator)'而不是过时的'iterator.next()'(假设你至少使用了2.6)。 2.请不要使用'_'作为变量名称。人们往往认为这是因为一些特殊的语法 - 使用“虚拟”或类似的方式避免了任何混淆。 – 2012-01-07 23:15:50

+0

感谢您的指点!更新。 – Acorn 2012-01-07 23:22:46

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

在最坏的情况下,这是O(n^2),而原始代码是O(n)。 – 2012-01-07 22:41:33

+0

当然还有优化的空间,包括对'list.index()'使用'start'参数。 – 2012-01-07 22:48:34

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

整洁。你可以在最后一行使用'list(ifilterfalse(c.send,values))'。 (我并不是说这会更好。) – 2012-01-07 23:30:07

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]

1

编写一个简单的功能与德尔工作列表中的切片:

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