Python成员限制测试?
我使用的一种方法有问题,该方法用于测试地理位置列表中的成员资格,并从未通过此检查的预算列表中删除条目。有趣的是,这个方法需要运行3次才能捕获100%的失败条目 budg元素示例:Python成员限制测试?,python,Python,我使用的一种方法有问题,该方法用于测试地理位置列表中的成员资格,并从未通过此检查的预算列表中删除条目。有趣的是,这个方法需要运行3次才能捕获100%的失败条目 budg元素示例: budg = ['KELOG_PSOD_32773 20131125 000327 73144652.3376898.6 9769.50', 'KELOG_PSOD_32774 201
budg = ['KELOG_PSOD_32773 20131125 000327 73144652.3376898.6 9769.50', 'KELOG_PSOD_32774 20131125 000327 74140034.3406629.9 4473.90']
geolist = ['KELOG_GEO_32773','KELOG_GEO_32775']
def remove_entry(budg, geolist):
for e in budg:
record = 'KELOG_GEO_' + e[11:e.index(' ')]
if record not in geolist:
print e
removed.append(budg.pop(budg.index(e)))
地理元素示例:
budg = ['KELOG_PSOD_32773 20131125 000327 73144652.3376898.6 9769.50', 'KELOG_PSOD_32774 20131125 000327 74140034.3406629.9 4473.90']
geolist = ['KELOG_GEO_32773','KELOG_GEO_32775']
def remove_entry(budg, geolist):
for e in budg:
record = 'KELOG_GEO_' + e[11:e.index(' ')]
if record not in geolist:
print e
removed.append(budg.pop(budg.index(e)))
我对每个列表都有大约2500个条目的列表运行此操作。截至今天,budg列表中存在44个不合格条目。运行此方法一次后,budg列表中始终存在7个误报。然后他们中的4人被抓到再次使用它。最后,在第三次运行中找到剩余的3个。我知道我可以在脚本中运行这个方法3次,然后一天调用一次,但这真的开始困扰我了
我尝试对列表进行反向排序,有趣的是,在第一次尝试时,我提取了44个失败条目中的37个,但其中一些条目将出现在第二次运行结果中,如果我不对列表进行反向排序,则第三次运行结果中也会出现
您是否知道我可能违反此代码对成员资格测试的任何限制?你们中有人以前见过类似列表的行为吗 您正在从
budg
中删除元素,同时在其上循环。执行以下操作时,for循环迭代器的不会更新其索引:
>>> lst = [1, 2, 3]
>>> for i in lst:
... print i
... lst.remove(i)
...
1
3
这里跳过了2
,因为迭代器首先处理lst[0]
,然后移动到lst[1]
,此时它来自一个包含[2,3]
的列表,而不是[1,2,3]
改用while
循环:
i = 0
while i < len(budg):
e = budg[i]
record = 'KELOG_GEO_' + e.split(None, 1)[0][11:]
if record not in geolist:
removed.append(budg.pop(i))
else:
i += 1
i=0
而我
现在,您可以直接控制正在处理的索引,并且在不删除元素时只增加i
。您不应该在迭代列表时从列表中删除元素。原因是,这会修改要删除的元素的索引,从而更改循环将继续其迭代的位置
您应该先确定要删除哪些元素,然后再删除它们。问题是您正在更改正在迭代的列表。避免这种情况的方法不止一种。一种简单易懂且快速的方法是创建一个新的列表,去掉您想要删除的项目,然后用它替换原来的列表。我的意思是:
budg = ['KELOG_PSOD_32773 20131125 000327 73144652.3376898.6 9769.50',
'KELOG_PSOD_32774 20131125 000327 74140034.3406629.9 4473.90']
geoset = {'KELOG_GEO_32773', 'KELOG_GEO_32775'} # note this is now a set
def remove_entry(budg, geoset):
cleaned = []
for e in budg:
record = 'KELOG_GEO_' + e[11:e.index(' ')]
if record in geoset: # keep it
cleaned.append(e)
budg[:] = cleaned
remove_entry(budg, geolist)
print 'budg:', budg
这种方法的另一个优点是,它可以简化为一行代码:
budg = [e for e in budg if 'KELOG_GEO_' + e[11:e.index(' ')] in geoset]
正如在修订后的代码开头的一篇评论中所指出的,我将geolist
改为geoset
,因为在集合中测试成员身份通常比在列表中检查成员身份要快得多(如果列表很大)。或者在列表中后退而不是前进;然后您可以一次而不是两次完成。您也可以使用for i in xrange(len(budg)-1,-1,-1):
向后跨过列表,然后您不必使用特殊的处理程序来有条件地修改计数器。@SilasRay:当然,但随后您还必须反转删除的,或者在开始时插入。这就足够了。我猜这可以归结为,与budg相比,删除的是否需要很长时间,哪一个是最好的。