我想知道我是否应该将我的数据结构作为集合或列表。大多数情况下我会设置操作,但最后我需要对其进行排序。
我想知道我是否应首先将集合设为列表,然后使用sorted(list(my_set))
,或者只是立即对集合sorted(my_set)
进行排序。可以说,我可能会考虑一个通用的“列表”阶段,因为在那个时间点有一个有序的可迭代可能有意义。
所以我决定测试它,希望列表更快。
基准:
import time
def sorter(x):
t1 = time.time()
for i in range(1000000):
sorted(x)
return time.time() - t1
数据:
one = range(1000)
a1 = list(one)
b1 = set(one)
sorter(a1)
# time: 16.5 s
sorter(b1)
# time: 20.7 s
然后我意识到它可能与这些元素已经到位的事实有关,并且记住了this amazing question & answer。
然后,我尝试了一些随机数据:
two = numpy.random.randint(1, 1000, 1000)
a2 = list(two)
b2 = set(two)
结果:
sorter(a2)
# time: 4min 49s
sorter(b2)
# time: 18.9 s
巨大的差异,发生了什么?
奖励:它甚至出现在一分钟的时间,sorted(set(a_list))
比sorted(a_list)
快得多。
确实在第二种情况下,可能存在重复的过滤,从而加快排序。
答案 0 :(得分:3)
我对您的代码进行了一些扩展,希望这能让您深入了解正在发生的事情:
import numpy
import uuid
import random
import time
def sorter(x):
t1 = time.time()
for i in range(10000):
sorted(x)
return time.time() - t1
def pr(name, x):
print('sorter {:<12s} {:<11} (length {:>4})'.format(
name, '{:.8}'.format(sorter(x)), len(x)))
a2sizes = []
b2sizes = []
for x in range(1000):
two = numpy.random.randint(1, 1000, 1000)
a2 = list(two)
b2 = set(two)
a2sizes.append(len(a2))
b2sizes.append(len(b2))
print 'average number of elements in a2', sum(a2sizes)/len(a2sizes)
n = sum(b2sizes)/len(b2sizes)
print 'average number of elements in b2', n
打印出来:
average number of elements in a2 1000
average number of elements in b2 632
这是因为随机数范围内的碰撞
print
pr('a2', a2)
# making a list of set gives you already sorted elements
y = list(b2)
pr('y', y)
random.shuffle(y)
pr('shuffled y ', y)
pr('b2', b2)
作为输出:
sorter a2 2.492537 (length 1000)
sorter b2 0.25028086 (length 633)
sorter y 0.19689608 (length 633)
sorter shuffled y 1.4935901 (length 633)
b2
会更快,因为逻辑上有更少的元素,但如果你首先列出一个集合必须有一些原因,那就更快了。如果你洗牌那个列表再次合乎逻辑,那么它再次是合乎逻辑的,并且当补偿列表的长度时,洗牌的结果非常接近a2的结果。
因此,我们尝试在列表中添加其他内容:
b3 = set()
for x in range(1000):
b3.add(uuid.uuid4())
print '\nuuid elements', len(b3)
a3 = list(b3)
pr('a3', a3)
random.shuffle(a3)
pr('shuffled a3', a3)
pr('b3', b3)
给出(我会对少于1000个元素感到惊讶):
uuid elements 1000
sorter a3 32.437758 (length 1000)
sorter shuffled a3 32.178433 (length 1000)
sorter b3 32.163802 (length 1000)
所以它必须与集合中的数字有关:
previous = -1
ordered = True
for popped in b2:
if popped < previous:
print 'popped', popped, previous
ordered = False
previous = popped
print '\nOrdered', ordered
给你:
Ordered True
set具有pop()
功能,而不是迭代,您可以尝试使用:
pop()方法
从集合中删除并返回任意元素。如果集合为空,则引发KeyError。
因此,让任意从集b2
中检索元素并查看是否有特殊内容:
previous = -1
ordered = True
while(b2):
popped = b2.pop()
if popped < previous:
print 'popped', popped, previous
ordered = False
previous = popped
print '\nOrdered', ordered
给出了相同的结果:
Ordered True
因此,任意检索一组数字的元素按顺序检索这些数字,独立于这些数字的排序方式。
由于迭代是列表制作一次检索元素以附加到列表的方式,list(b2)
的结果是一个有序列表,并使用Python中使用的Timsort算法快速排序