问题
我的关注点如下:我将一个相对性较大的数据集存储在一个经典的python列表中,为了处理数据,我必须多次迭代列表,对这些元素执行一些操作,并经常从列表中弹出一个项目。
似乎从Python列表中删除一个项目花费O(N),因为Python必须将元素上方的所有项目复制到一个地方。 此外,由于要删除的项目数量与列表中元素的数量大致成比例,因此将导致O(N ^ 2)算法。
我希望找到一个经济高效的解决方案(时间和记忆)。 我研究了在互联网上可以找到的内容,并总结了下面的不同选项。 哪一个是最好的候选人?
保持本地索引:while processingdata:
index = 0
while index < len(somelist):
item = somelist[index]
dosomestuff(item)
if somecondition(item):
del somelist[index]
else:
index += 1
这是我最初想出的解决方案。
向后走:while processingdata:
for i in xrange(len(somelist) - 1, -1, -1):
dosomestuff(item)
if somecondition(somelist, i):
somelist.pop(i)
这避免了增加索引变量,但最终的代价与原始版本相同。
列一个新的清单:while processingdata:
for i, item in enumerate(somelist):
dosomestuff(item)
newlist = []
for item in somelist:
if somecondition(item):
newlist.append(item)
somelist = newlist
gc.collect()
这是一个非常天真的策略,以消除元素从一个列表,并需要大量的内存,因为几乎完整的副本列表必须作出。
使用清单理解:while processingdata:
for i, item in enumerate(somelist):
dosomestuff(item)
somelist[:] = [x for x in somelist if somecondition(x)]
这是非常优雅的,但在掩盖之下,它再一次遍历整个列表,并且必须复制其中的大多数元素。
使用过滤器功能:while processingdata:
for i, item in enumerate(somelist):
dosomestuff(item)
somelist = filter(lambda x: not subtle_condition(x), somelist)
这还会创建一个占用大量RAM的新列表。
使用itertools的筛选函数:from itertools import ifilterfalse
while processingdata:
for item in itertools.ifilterfalse(somecondtion, somelist):
dosomestuff(item)
此版本的筛选器调用不会创建新列表,但不会对每一项调用doomestuff,从而破坏算法的逻辑。我列入这个例子只是为了创建一个详尽的清单。
边走边移动列表上的项目while processingdata:
index = 0
for item in somelist:
dosomestuff(item)
if not somecondition(item):
somelist[index] = item
index += 1
del somelist[index:]
这是一个微妙的方法,似乎成本效益。 我认为它会移动每个项目(或指向每个项目的指针?)一次导致O(N)算法。 最后,我希望Python能够足够聪明地在最后调整列表的大小,而不需要为列表的新副本分配内存。 但不知道。
放弃Python列表:class Doubly_Linked_List:
def __init__(self):
self.first = None
self.last = None
self.n = 0
def __len__(self):
return self.n
def __iter__(self):
return DLLIter(self)
def iterator(self):
return self.__iter__()
def append(self, x):
x = DLLElement(x)
x.next = None
if self.last is None:
x.prev = None
self.last = x
self.first = x
self.n = 1
else:
x.prev = self.last
x.prev.next = x
self.last = x
self.n += 1
class DLLElement:
def __init__(self, x):
self.next = None
self.data = x
self.prev = None
class DLLIter:
etc...
这种类型的对象以有限的方式类似于python列表。 但是,保证删除元素O(1)。 我不想去这里,因为这需要大量的代码重构几乎无处不在。