是否从Python中廉价的列表前面删除了一个元素?

时间:2017-02-02 22:20:43

标签: python list python-3.x optimization

我正在编写一个程序,它在数据列表的前面或后面执行大量删除操作,而不是中间删除。

我明白删除最后一个元素很便宜,但删除第一个元素怎么样?例如,假设列表A的地址位于4000,因此元素0位于4000,元素1位于4001

删除元素0然后只需让编译器将列表A的地址放在4001,或者将1处的元素4001转移到4000位于1的位置,并将所有其他元素向下移动func getMapAnnotations() -> [Stands] { var annotations:Array = [Stands]() print("ANNOTATIONS") //load plist file var stands: NSArray? if let path = Bundle.main.path(forResource: "stands", ofType: "plist") { stands = NSArray(contentsOfFile: path) } //iterate and create annotations if let items = stands { for item in items { let lat = (item as AnyObject).value(forKey: "lat") as! Double let long = (item as AnyObject).value(forKey: "long")as! Double let annotation = Stands(latitude: lat, longitude: long) let tit = (item as AnyObject).value(forKey: "title") as! String let numb = (item as AnyObject).value(forKey: "no") as! Int annotation.title = "\(numb) \(tit)" annotation.no = numb annotations.append(annotation) } } return annotations }

2 个答案:

答案 0 :(得分:41)

不,它不便宜。从列表前面删除元素(例如,使用list.pop(0))是O(N)操作,应该避免 。同样,在开头插入元素(使用list.insert(0, <value>))同样效率低下。

这是因为,在调整列表大小后,必须移动它的元素。对于CPython,l.pop(0)案例,this is done with memmovel.insert(0, <value>)the shifting is implemented with a loop through the items stored

列表是为上的快速随机访问O(1)操作而构建的。

但是,由于您通常会执行此操作,因此应考虑使用deque from the collections module(在评论中建议使用@ayhan)。 deque上的文档还突出显示list对象不适合这些操作:

  

虽然列表对象支持类似的操作,但它们针对快速固定长度操作 O(n)内存移动成本进行了优化pop(0)和{{1} } 更改基础数据表示的大小和位置的操作。

(强调我的)

insert(0, v)数据结构为deque / O(1)appendleft / popleft双方(开始和结束)提供append复杂性分别为开始和结束的方法。

当然,对于小尺寸,这会产生一些额外的空间要求(由于pop的结构),这通常应该是无关紧要的(并且@juanpa在评论中指出,并不总是持有随着列表的大小增长。最后,正如@ ShadowRanger富有洞察力的评论所指出的那样,如果序列大小非常小,那么从前面弹出或插入的问题就会变得微不足道,以至于它变得毫无顾虑。

因此,简而言之,对于包含多个项目的列表,如果您需要双方快速追加/弹出,请使用deque,否则,如果您要随机访问并追加到最后,请使用{{1} }第

答案 1 :(得分:16)

从Python的列表前面删除元素是O(n),而从collections.deque的末尾删除元素只是O(1)。因此,deque对于您的目的来说是很好的,但应该注意的是,从双端队列中间访问或添加/删除比列表更昂贵。

删除O(n)成本是因为CPython中的列表只是作为指针数组实现,因此您对每个元素的转换成本的直觉是正确的。

这可以在Wiki上的Python TimeComplexity page中看到。