jdm*_*jdm 20 python sorting optimization
在python中获取排序,唯一列表的禁区方法是什么?(我有一个可清洗的东西列表,并希望有一些我可以迭代的东西 - 无论列表是否被修改到位,或者我得到一个新的列表,或者是一个可迭代的.在我的具体用例中,我'使用一次性列表执行此操作,因此就可以提高内存效率.)
我见过类似的解决方案
input = [5, 4, 2, 8, 4, 2, 1]
sorted(set(input))
Run Code Online (Sandbox Code Playgroud)
但在我看来,首先检查唯一性然后排序是浪费的(因为当您对列表进行排序时,您基本上必须确定插入点,因此将唯一性测试作为副作用).也许还有更多类似于unix的东西
cat list | sort | uniq
Run Code Online (Sandbox Code Playgroud)
只是在已经排序的列表中选择连续重复?
请注意" 在Python中使用最快化的列表方法 "这个问题 ,列表没有排序,并且' 在Python列表中进行排序加uniq的最简洁方法是什么?'要求最干净/最pythonic的方式,并且接受的答案表明sorted(set(input)),我正在努力改进.
Bak*_*riu 25
我相信这sorted(set(sequence))是最快的做法.是的,set在序列迭代,但是这是一个C级循环,这是很多比你的循环将在蟒蛇的水平做更快.
请注意,即使groupby你仍然拥有O(n) + O(nlogn) = O(nlogn)并且最糟糕的是groupby需要一个python级别的循环,这会大大增加其中的常量,O(n)从而最终获得最差的结果.
在谈到CPython时,优化事物的方法就是在C级别尽可能多地做到(请参阅此答案以获得另一个反直觉性能的示例).要获得更快的解决方案,您必须在C扩展中重新实现排序.即便如此,祝你获得像python的Timsort一样快的东西!
"规范解决方案"与groupby解决方案的小比较:
>>> import timeit
>>> sequence = list(range(500)) + list(range(700)) + list(range(1000))
>>> timeit.timeit('sorted(set(sequence))', 'from __main__ import sequence', number=1000)
0.11532402038574219
>>> import itertools
>>> def my_sort(seq):
... return list(k for k,_ in itertools.groupby(sorted(seq)))
...
>>> timeit.timeit('my_sort(sequence)', 'from __main__ import sequence, my_sort', number=1000)
0.3162040710449219
Run Code Online (Sandbox Code Playgroud)
你可以看到它慢了3倍.
jdm提供的版本实际上更糟糕:
>>> def make_unique(lst):
... if len(lst) <= 1:
... return lst
... last = lst[-1]
... for i in range(len(lst) - 2, -1, -1):
... item = lst[i]
... if item == last:
... del lst[i]
... else:
... last = item
...
>>> def my_sort2(seq):
... make_unique(sorted(seq))
...
>>> timeit.timeit('my_sort2(sequence)', 'from __main__ import sequence, my_sort2', number=1000)
0.46814608573913574
Run Code Online (Sandbox Code Playgroud)
慢了近5倍.请注意,使用seq.sort()然后make_unique(seq)和make_unique(sorted(seq))实际上是相同的事情,因为Timsort使用O(n)空间总是有一些重新分配,所以使用sorted(seq)实际上并没有改变太多的时间.
jdm的基准测试给出了不同的结果,因为他使用的输入太小,因此所有时间都是由time.clock()调用完成的.
也许这不是您正在寻找的答案,但无论如何,您应该考虑到这一点。
基本上,您在列表上有 2 个操作:
unique_list = set(your_list) # O(n) complexity
sorted_list = sorted(unique_list) # O(nlogn) complexity
Run Code Online (Sandbox Code Playgroud)
现在,你说“在我看来,首先检查唯一性然后排序是浪费的”,你是对的。但是,这个多余的步骤到底有多糟糕?取 n = 1000000:
# sorted(set(a_list))
O(n) => 1000000
o(nlogn) => 1000000 * 20 = 20000000
Total => 21000000
# Your fastest way
O(nlogn) => 20000000
Total: 20000000
Run Code Online (Sandbox Code Playgroud)
速度增益:(1 - 20000000/21000000) * 100 = 4.76 %
对于 n = 5000000,速度增益:~1.6 %
现在,这种优化值得吗?