【发布时间】:2018-03-20 15:35:09
【问题描述】:
假设我有这个简单的类:
class Foo(object):
def __init__(self, number, name):
self.number = number
self.name = name
以及 Foo 实例的列表:
l = [Foo(10, 'a'), Foo(9, 'a'), Foo(8, 'a'), Foo(7,'a'), Foo (5, 'b'), Foo (4, 'b') ,Foo (3, 'b')]
假设“name”属性只能是“a”或“b”。
提取“name”为“a”(或“b”)的所有对象的子列表的最快方法是什么?请注意,此操作可能会被调用数百万次,这就是我想尽可能优化它的原因。
请注意,列表的构建方式使得列表的前半部分或后半部分中的所有元素都“组合在一起”。该列表是对称的,并按递减属性“数字”排序。 编辑:不一定有相同数量的“a”和“b”。
我是怎么做的:
一开始我只是在做一个for循环:
sublist = []
for o in l:
if o.name == 'a'
sublist.append(o)
然后我尝试了列表理解:
sublist = [o for o in l if o.name=='a']
但这似乎大致相同,如果不是慢一点的话。
无论哪种方式,这些都没有利用所有属性已经在原始(排序)列表中“组合在一起”的假设。即使不再需要它也会继续循环。速度非常重要,所以我需要它尽可能地高效。
【问题讨论】:
-
如果不遍历整个列表,就无法对所有需要的元素进行分组。我只能建议您在允许的情况下使用生成器。
-
如果只有 'a' 和 'b' 值,并且 'a' 总是在前,那么你可以使用二分搜索找到最后一个 'a' 元素,然后使用切片来获取所有 ' a' 元素。 O(logN) 找到最后一个 'a' 元素,但它仍然是 O(N) 来制作列表的副本
-
它们是按字典顺序排列的还是只是成簇的?你能优化更高吗?在建立清单之前?这种数据结构不适合这类事情。
-
好吧,我完全错过了'a'和'b'元素的数量相同。二进制搜索在这里没用,因为您可以按照 Shaido 的建议在 O(1) 中找到中间点
-
那么天真的方法(带循环)应该不超过 1 秒。您确定这是优化的正确位置吗?另外,正如我已经说过的,如果你想复制这个列表,无论你能多快找到最后一个“a”元素,它仍然会花费 O(N)。不过,我正在准备完整的答案。
标签: python performance list