Python 如何快速查找数组中未配对的元素?

Python 如何快速查找数组中未配对的元素?,python,python-3.x,optimization,Python,Python 3.x,Optimization,我正在练习一些来自Codibility的问题。但是,每次我运行这些问题时,我的性能(运行时)得分都很低(25%)。你能帮助我知道如何改进我的代码以便获得更好的分数吗 问题是: def solution(A): # write your code in Python 3.6 lis=[i for i in A if A.count(i) ==1] return lis[0] 编写一个函数: def solution(A) 给定一个由满足上述条件的N个整数组成的数组A,返回未配对

我正在练习一些来自Codibility的问题。但是,每次我运行这些问题时,我的性能(运行时)得分都很低(25%)。你能帮助我知道如何改进我的代码以便获得更好的分数吗

问题是:

def solution(A):
# write your code in Python 3.6
    lis=[i for i in A if A.count(i) ==1]
    return lis[0]
编写一个函数:

def solution(A)
给定一个由满足上述条件的N个整数组成的数组A,返回未配对元素的值

例如,给定一个数组,使得:

  A[0] = 9  A[1] = 3  A[2] = 9
  A[3] = 3  A[4] = 9  A[5] = 7
  A[6] = 9
该函数应返回7,如上面示例中所述

我的代码是:

def solution(A):
# write your code in Python 3.6
    lis=[i for i in A if A.count(i) ==1]
    return lis[0]
输出:

def solution(A):
# write your code in Python 3.6
    lis=[i for i in A if A.count(i) ==1]
    return lis[0]
媒介2 “中等随机试验n=100003✘超时错误 杀死。达到硬限制:6.000秒”


这是因为
list.count
每次都会搜索整个列表,即O(N)*N或N**2。您可以使用来计算一个项目一次或一次出现的次数,查找次数为O(1),因为它是一个字典:

从集合导入计数器
def溶液(A):
c=计数器(A)
#这将迭代所有键/值对
#最坏的情况是N个元素长
返回[k表示k,如果v==1,则返回c.items()中的v]
要显示速度的增加:

python-m timeit-s“来自随机导入randint;A=[randint(0500)表示范围(10000)中的i]”x=[A表示范围(10000)中的A,如果A.count(A)==1]“
10个循环,最好为3:957毫秒/循环
python-m timeit-s“从随机导入randint;从集合导入计数器;A=[randint(0500)表示范围(10000)中的i];c=Counter(A)”“x=[s表示s,v表示c.items(),如果v==1]”
10000个循环,最好3个:每个循环20.1 usec
尽管我每次都创建一个随机列表,但在20次试验中,
计数器
实现的平均最佳运行时间为20.2us,而
list.count
实现的平均最佳运行时间为962.1ms。因此,即使每次运行都不完全是苹果对苹果,我认为平均显示本身

尝试以下方法:

import collections 

k = collections.Counter(A)
return [ i for i in k if k[i] == 1]

带有
itertools.groupby()
的版本的性能大约是带有
集合的版本的3倍。计数器

import collections
from itertools import groupby
import timeit

l = [9, 3, 9, 3, 9, 7, 9]

def fn1(lst):
    return [v for v, g in groupby(sorted(lst)) if len([*g]) == 1]

def fn2(lst):
    k = collections.Counter(lst)
    return [i for i in k if k[i] == 1]

print(timeit.timeit(lambda: fn1(l), number=100_000, globals=globals()) )
print(timeit.timeit(lambda: fn2(l), number=100_000, globals=globals()) )
印刷品:

0.11646193999331445
0.33489679799822625

对于堆栈来说,这可能是一个好问题site@G.Anderson非常感谢。“我不知道。”安德烈·凯斯利·多谢也尝试过这种方法。但Codibility对这两种方法的评分相同。感谢您的帮助。与优化相关的问题适用于堆栈溢出,无需将它们转移到代码审阅。问题中所描述的问题相对较小且重点突出,因此我不确定为什么应用“过于宽泛”的近距离推理。此外,根据答案,可以通过了解适当的python函数来解决问题,这正是堆栈溢出的目的。投票赞成重新开放。谢谢你,它起作用了。早些时候,他们不允许我导入numpy,所以我认为不允许导入额外的LIB。无论如何,这是可行的。非常感谢:)@AkhilT Counter只是一个专门用于计数的dict。您可以使用简单的dict@juanpa.arrivillaga谢谢你提供的信息。这很有帮助。小优化:通过将
[k表示c中的k,如果c[k]=1]
更改为
[k表示c中的k,如果v==1]
来避免嵌套查找和
dict
查找开销。对于较小的输入,速度可能稍慢,但对于较大的输入,应能更好地扩展。此外,除非练习需要,否则不要将导入放在函数本身中(重新导入模块非常昂贵,至少在CPython上是如此,即使模块已经加载并缓存,这要归功于极其复杂的模块查找机制)。@ShadowRanger true,我比较快地完成了这项工作,我会把它添加为一个稍微慢一点的编辑器,但是
sum(1代表g)
不会将整个列表读入内存,而不是
len([*g])
。我怀疑这里的性能改进是输入量小的结果;对于三个独特的项,
排序的
O(n log n)复杂性几乎不重要,
groupby
实现中的低效性无关紧要,而
计数器
的大致计算复杂性没有机会显现出来。根据我的经验,
groupby
比人们想象的要慢得多(有时即使输入已经排序,也会输给
计数器
,因此不需要调用
sorted
。@Error syntacticalreforse:或者过分使用。:-)@暗影游侠让我们撕开。。。虽然在我的机器(AMD 2400G)上,该解决方案似乎是最慢的(至少从在repl.it上测试来看是如此)@ShadowRanger,但使用
groupby()
的版本在输入阵列的长度达到85-90之前速度更快。