如果我有一个列表,例如L=[1,8,8,8,1,3,3,8]
,并且保证每个元素出现偶数次,那么我如何制作一个L
的所有元素现在出现N/2
次的列表。 因此,由于1
发生了2
次,现在应该发生一次。 因为8
出现4
次,所以现在应该出现两次。 由于3
发生了两次,所以应该发生一次。
因此新列表将类似于k=[1,8,8,3]
做这件事最快的方法是什么? 我为每个元素都做了list.count()
,但是非常慢。
如果顺序不重要,一种方法就是只在排序之后获取奇数或偶数索引。 这些列表将是相同的,所以你只需要其中的一个。
l = [1,8,8,8,1,3,3,8]
l.sort()
# Get all odd indexes
odd = l[1::2]
# Get all even indexes
even = l[::2]
print(odd)
print(odd == even)
结果:
[1, 3, 8, 8]
True
使用计数器跟踪每个元素的计数
from collections import Counter
l = [1,8,8,8,1,3,3,8]
res = []
count = Counter(l) # its like dict(1: 2, 8: 4, 3: 2)
for key, val in count.items():
res.extend(val//2 * [key])
print(res)
# output
[1, 8, 8, 3]
由于您保证列表的每个元素都是2的倍数,因此在构建输出列表时构建计数器会更快,而不是先构建计数器(或排序),然后再使用它。
l = [1,8,8,8,1,3,3,8]
count={}
res=[]
for i in l:
if i in count: count[i]+=1
else: count[i]=1
if count[i]%2: res.append(i)
print(res)
输出量
[1,8,8,3]
编辑比较每种方法的时间/费用
使用TimeIt
模块表明,这种方法比首先使用计数器快2.7倍。
即。
def one():
l = [1,8,8,8,1,3,3,8]
count={}
res=[]
for i in l:
if i in count: count[i]+=1
else: count[i]=1
if count[i]%2: res.append(i)
#print(res)
def two():
from collections import Counter
l = [1,8,8,8,1,3,3,8]
res = []
count = Counter(l) # its like dict(1: 2, 8: 4, 3: 2)
for key, val in count.items():
res.extend(val//2 * [key])
o=timeit.Timer(one)
t=timeit.Timer(two)
print(o.timeit(100000))
print(t.timeit(100000))
print(o.timeit(100000))
print(t.timeit(100000))
输出(秒)
0.28666
0.80822
0.28678
0.80113
如果顺序不重要,那么Wimanicesir的方法将被优先考虑,其加速比为4倍,结果为0.07037(比计数器方法快11倍)。
我怀疑在two
(无序)中使用counter
方法可能会在导入时出现明显的膨胀或减慢,因此我测试了“先计数,后编译结果”方法,同时使用这里的简单方法从one
(有序)进行计数
count={}
for i in l:
if i in count: count[i]+=1
else: count[i]=1
它比counter
快得多。 在定义的两个
测试中替换计数器
会导致0.31而不是0.80的时间。 但是,在计数过程中,编译(有序)结果的速度稍微快一些,如two
中所示。 对于无序的结果,使用Wimanicesir的方法要快得多。