我正在编写一个程序,它在数据列表的前面或后面执行大量删除操作,而不是中间删除。
我明白删除最后一个元素很便宜,但删除第一个元素怎么样?例如,假设列表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
}
?
答案 0 :(得分:41)
不,它不便宜。从列表前面删除元素(例如,使用list.pop(0)
)是O(N)
操作,应该避免 。同样,在开头插入元素(使用list.insert(0, <value>)
)同样效率低下。
这是因为,在调整列表大小后,必须移动它的元素。对于CPython,l.pop(0)
案例,this is done with memmove
,l.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中看到。