动态从数组中删除元素并减小数组的大小

时间:2019-05-10 20:33:44

标签: python

需要一种在迭代时删除元素后固定列表大小的解决方案。

无法创建新列表,因为存在较大问题(800次迭代),并且每次创建新列表在计算上都是昂贵的

list = [1,2,3,4,5,6,7,8,9,10]

for i in range (len(list)):
    if a[i] < 6:
        del a[i]

输出应该是原始列表,现在带有值

[6,7,8,9,10]

4 个答案:

答案 0 :(得分:1)

仅覆盖当前列表

lst = [1,2,3,4,5,6,7,8,9,10]

lst =[i for i in lst if i>=6]

# lst = [6,7,8,9,10]

答案 1 :(得分:1)

有关性能评估,请参见此答案末尾的UPDATE

如果仅要删除列表中的一个元素(或列表开头的元素),则可能需要查找索引,而不要遍历所有元素:

index = lst.index(6)
del lst[:index]

如果在遍历列表时担心索引偏移,则可以跟踪已删除条目的数量并相应地计算实际索引:

originalLen = len(lst)
for originalIndex in range(originalLen):
    i = originalIndex - originalLen + len(lst)
    if lst[i] < 6:
        del lst[i]

您甚至可以通过创建一个为您做家务的迭代器来对此进行概括:

def stableIndexes(lst):
    oLen = len(lst)
    for oi in range(oLen): yield oi - oLen + len(lst)

for i in stableIndexes(lst):
    if lst[i] < 6:
        del lst[i]

如果要删除多个项目,则可以创建索引列表以在循环结束时以相反的顺序删除和处理它们:

indexes = []
for i,a in enumerate(lst):
    if a > 2 and a < 5:
        indexes.append(i)
for index in reversed(indexes):
    del lst[index] 

或者您可以按照相反的顺序处理列表,并在删除索引时将其删除,而不会混淆索引:

for i in range(len(lst)-1,-1,-1):
    if lst[i] > 2 and lst[i] < 5:
        del lst[i]

另一种方法是在删除至少一个项目后手动移动后续项目,并在末尾截断列表:

i = 0
for index,a in enumerate(lst):
    if a > 2 and a < 5:
        continue 
    if i < index:
        lst[i] = a
    i += 1
del lst[i:]  

最后,另一种方法是将“无”分配给要删除的项目,并在后续迭代中跳过“无”值:

for i,a in enumerate(lst):
    if a is None: continue
    if a > 2 and a < 5:
        lst[i] = None
    ...

UDATE

我进行了一些性能测试,从1,000,000个元素列表中删除了条目。事实证明,使用列表理解(即制作列表的第二个副本)比我上面描述的所有方案都快:

Method                              del 1 in 13   del only 1
----------------------------------  -----------   ----------
New list (using comprehension):     0.00650       0.00799
Assign None to deleted items:       0.00983       0.01152
Manually shifting elements:         0.01558       0.01741
Delete as you go in reverse order:  0.07436       0.00942
List of indexes to delete:          0.09998       0.01044

因此,创建新列表的“计算上昂贵”的理论在实践中并不成立。与所有其他方法相比,就处理时间而言,它实际上是最经济的方法。

这很可能是由COW(写时复制)内存管理引起的,该管理将在您更改列表中的某些内容后立即分配内存。因此,总会(内部)创建一个新列表。

通过自己显式创建一个新列表,您可以利用此内存分配,并节省列表内存空间内数据的任何其他移位。

最后,您应该让Python处理这些问题。

答案 2 :(得分:0)

首先,使用列表推导更容易:

lst = [1,2,3,4,5,6,7,8,9,10]
t = [x for x in lst if x >= 6]
print(t)

如果不允许创建新的list对象,则始终可以使用生成器表达式:

lst = [1,2,3,4,5,6,7,8,9,10]
g = (x for x in lst if x >= 6)

for val in g:
    print(val)

答案 3 :(得分:0)

一种安全的解决方案(如果修改了一个列表,在任何程度上对其进行迭代都可以称为“安全”),请向后迭代:

n = len(list_)
for i in xrange(n):
  idx = n - i - 1
  if list_[idx] < 6:
    del list_[idx]

这样,您至少不会对列表的未更改部分产生影响。

相关问题