如果我有一个列表说,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 indexesodd = l[1::2]# Get all even indexeseven = l[::2]print(odd)print(odd == even)
结果:
[1, 3, 8, 8]True
使用计数器来跟踪每个元素的计数
from collections import Counterl = [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.286660.808220.286780.80113
如果顺序不重要,则最好使用Wimanicesir的方法,将其速度提高4倍,结果为0.07037(比使用反方法快11倍)。
更新 我怀疑Counter
在two
(无序)中使用该方法可能会导致明显的膨胀或导入速度减慢,因此我测试了“先计数,后编译结果”方法,同时从此处one
(有序)使用简单方法进行计数
count={}for i in l: if i in count: count[i]+=1 else: count[i]=1
这比快得多Counter
。更换Counter
在two
测试的定义导致了0.31,而不是0.80的时间。与一样two
,在计数过程中编译(排序)结果的速度仍然稍快一些。对于无序结果,使用Wimanicesir的方法要快得多。
如果您不关心保留相对顺序,则可以先使用来获取每个元素的计数collections.Counter
,然后创建一个新列表,每个元素重复一半的次数。
>>> from collections import Counter>>> from itertools import chain>>> list(chain.from_iterable([key]*(count//2) for key, count in Counter(l).items()))[1, 8, 8, 3]
代替使用为列表的每个可能元素跟踪整数的计数器,请尝试使用字典将元素映射到布尔值。第一次看到它们时将其映射为true,然后在每次翻转位时将其映射为真,如果为true,则跳过该元素。
也许这个。
newList = [] for number in l: if(newList.count(number) < l.count(number)/2): newList.append(number)print(newList)
会保留一次访问次数不均的所有项目的列表。然后您遍历所有列表项。
在其他语言中,可能会使用一些map()或filter()方法,但这是一些简单的代码,因为我对python的了解不够!:)
l = [1,8,8,8,1,3,3,8]seen = []result = []for num in l: if num in seen: seen.remove(num) #result.append(num) #print every even appearance else: seen.append(num) result.append(num) #print every odd appearanceif len(seen)==0: print(result)else: print("Error: uneven elements found:", seen)
最后,受访数组应该为空,因此您可以在返回结果数组之前将其用作完整性检查。
编辑:这是带有过滤器的版本,可返回奇数外观
l = [1,8,8,8,1,3,3,8]seen = []result = list(filter(lambda x: seen.append(x) is None if x not in seen else not seen.remove(x) is None, l))if len(seen)==0: print(result)else: print("Error: uneven elements found:", seen)
而这个返回偶数出现:
l = [1,8,8,8,1,3,3,8]seen = []result = list(filter(lambda x: seen.remove(x) is None if x in seen else not seen.append(x) is None, l))if len(seen)==0: print(result)else: print("Error: uneven elements found:", seen)