Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何快速比较列表和集合?_Python_Algorithm_Performance_Set_Low Latency - Fatal编程技术网

Python 如何快速比较列表和集合?

Python 如何快速比较列表和集合?,python,algorithm,performance,set,low-latency,Python,Algorithm,Performance,Set,Low Latency,假设我有一张清单 l = [1, 1 , 1, 2, 3, 4, 5, 5] 和两个长度相等的不相交的集 a=(1,3)和b=(2,5) 我想得到l中的元素,也就是a和b中的元素,就像 [1,1,1,3]和[2,5,5] 我尝试了列表理解,比如[x代表x,如果x代表x,如果x代表a],但是如果l,a和b的长度是10^5,那么这需要很长时间 编辑:这些集合是长度相等的不相交集合 编辑:我需要做的是计算l中a中常见的元素(有重复项)减去b中l元素(也有重复项)。因此,上面的示例应该输出1。问题是列

假设我有一张清单

l = [1, 1 , 1, 2, 3, 4, 5, 5]
和两个长度相等的不相交的集

a=(1,3)
b=(2,5)

我想得到
l
中的元素,也就是
a
b
中的元素,就像

[1,1,1,3]
[2,5,5]

我尝试了列表理解,比如
[x代表x,如果x代表x,如果x代表a]
,但是如果
l
a
b
的长度是10^5,那么这需要很长时间

编辑:这些集合是长度相等的不相交集合

编辑:我需要做的是计算
l
a
中常见的元素(有重复项)减去
b
l
元素(也有重复项)。因此,上面的示例应该输出
1
。问题是列表和集合的长度是否与10E5一样长。使用过滤器和itertools仍然需要很长时间


编辑:我现在知道了!显然,我必须用
set()
包装输入集!起初我没有这样做(我只是通过
input().split()
)获得的),因为输入已经是唯一的,但不知道列表和集合非常不同,集合速度更快!好的,直到我。

您可以使用
itertools
模块中的
chain
repeat
函数:

>>> from itertools import repeat,chain
>>> a={1,3}
>>> list(chain.from_iterable((repeat(i,l.count(i)) for i in a)))
[1, 1, 1, 3]
注意:作为一种更有效的方法,您可以为
a
使用
set
容器,该容器的成员身份检查复杂度为O(1),如果不需要结果作为列表,
链,则无需调用
列表

或者,作为一种非常优化的方法,您可以使用
numpy
,当您处理庞大的列表时,这种方法特别强大:

>>> import numpy as np
>>> l = np.array([1, 1 , 1, 2, 3, 4, 5, 5])
>>> a = (1, 3)
>>> l[np.in1d(l,a)]
array([1, 1, 1, 3])

我很想看看这是如何处理您的数据集的

from pandas import Series
l = Series([1, 1 , 1, 2, 3, 4, 5, 5])
a = Series((1, 3))
b = Series((3, 5))
a_answer, b_answer = list(l[l.isin(a)]), list(l[l.isin(b)])
原因:Pandas的调用实现级别低于Python,所以根据数字的数据类型,它可能比纯Python解决方案更适合您

快点? 由于Kasramvd提出了一种智能的
np.inad()
方法,同时还提出了Wesley的马力
框架,让我来设定量化标准,以便能够处理单个解决方案的质量

让我们既公平又定量: 更多,一旦游戏中有10E+5项处理效率和速度处理内存处理矢量化潜在的和(可能)隐藏的不良副作用,CPU缓存延迟掩蔽更差或更好的非CPU数据访问时间(以及更多的巨魔)这些都是敌人,我们必须在生产中与之共存:


总结: 内森的
set
方法对于所有测试量表来说都要快得多

Nathan的方法处理小型、
1E+4
1E+6
缩放集的速度要快得多,这得益于
集合
-s中独特元素的python散列集合中隐藏的优越搜索能力(正如
集合
类型正是为其引入的)

然而,
O(m*n)
/
O(n^2)
无法证明

这些假定的复杂性模型应该意味着,随着
m
n
规模的增长,与基于相同
list
/
set
set
方法相比,基于
numpy
的方法的不利性能惩罚将随着
m
的增加而加速,
n
-s

不断增长的
set
-尺度表明初始边缘在更大尺度上变得更小

1:3
1E+4
等级上的速度优势降级为仍然适当,但在
1E+6等级上的一些
1:2速度优势较小

实际的代码执行使得任务O(m*n)/O(n^2)-复杂性的先验假设无法在活体内确认。


如何测试它? 下一步重新运行已编译的满量程

getLinA( npL[:1E+9], npA[:1E+9] )

与内森·戴维斯(Nathan Davis)的想法交流激发了事后讨论 计时:请参考实际代码执行工件出现时计时结果的差异(缓存脏度的差异)

对于缩放为1E+4和1E+6大小的对象:

>>> aStopWATCH.start();NathanListPROCESSOR( aLIST, setA, setB );aStopWATCH.stop()
-1
  2582L
  2673L
  2529L
  2524L
  2888L
  2693L

>>> aStopWATCH.start();getLISTinSET( npLIST, npSetA, npSetB );aStopWATCH.stop()
0
129983L
 12068L
 10699L
 10930L
 10857L
 10999L
 10954L
 10994L
numba
的帮助下:

>>> @numba.jit
... def numba_getLISTinSET( npList, npSetA, npSetB ):
...     return ( len(       npList[ np.in1d( npList, npSetA ) ] ) -
                 len(       npList[ np.in1d( npList, npSetB ) ] )
                 )
>>> aStopWATCH.start();numba_getLISTinSET( npLIST, npSetA, npSetB );aStopWATCH.stop()
0
165320L
  7047L
  7328L
  7378L
  7898L
  7519L
  7556L
  7277L
  7296L
  7292L
  7303L
  7302L
  7426L
  7369L
  7307L
最后,几乎是1E+6的规模:

>>> setA = generateSet( 1000000 )
>>> len( setA )                                      # the cost of uniqueness
235836
>>> setB = generateSet( 1000000 )

>>> npSetA = np.array( list( setA ), dtype = np.int )
>>> npSetB = np.array( list( setB ), dtype = np.int )

>>> aLIST = list( ( np.random.random( 1000000 * 1.1 + 10 ) * 1000000 * 10000 ).astype( np.int ) )[:1000000]

>>> len( aLIST )
1000000
>>> npLIST = np.array( aLIST, dtype = np.int )

#----------------------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv-------------
#---------------------|                                           |-------------
>>> aStopWATCH.start();numba_getLISTinSET( npLIST, npSetA, npSetB );aStopWATCH.stop()
6
406061L
403946L
409831L
409329L
408920L

#----------------------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv-------------
#---------------------|                                       |-------------
>>> aStopWATCH.start();NathanListPROCESSOR( aLIST, setA, setB );aStopWATCH.stop()
785334
200755L
196791L
195540L
196606L
202483L
197094L
199481L
196651L
200969L
198856L
202039L
200152L
202364L

根本的问题是,您没有为作业使用适当的数据结构。 在这种情况下,使用元组表示集合对于小集合可能是合适的, 但对于大型集合,您可以期望搜索平均值 列表中每个元素的集合组合大小的一半 这实际上是其中的一组。 对于列表中不在任一集合中的每个元素, 我们必须搜索这两个集合的所有元素来确定它

所以任何基于这些数据结构的算法 (即,使用元组表示集合) 最多为
O(m*n)
,其中
m
是列表的大小 而
n
是集合的大小

我们真的没有办法减少
m
组件 -我们必须检查列表中的每个元素以确定哪一组 (如有的话)它属于

但是,我们可以减少
n
组件。 怎么用?通过为我们的集合使用更高效的数据结构

幸运的是,这并不难,因为Python包含一个内置的
set
类型。 因此,第一步是构造两个集合:

a = set((1, 3))
b = set((2, 5))
现在,我们可以轻松(高效)确定元素
e
是否在以下集合之一中:

e = 1
e in a # => True
e in b # => False
现在,我们只需要循环输入列表并累积结果:

l = [1, 1, 3, 2, 5, 7, 8, 3, 2, 1]
result = 0 # accumulator for result
for e in l:
  if e in a:
    result += 1
  elif e in b:
    result -= 1

print result # prints "2"
你能用不同的吗
>>> @numba.jit
... def numba_getLISTinSET( npList, npSetA, npSetB ):
...     return ( len(       npList[ np.in1d( npList, npSetA ) ] ) -
                 len(       npList[ np.in1d( npList, npSetB ) ] )
                 )
>>> aStopWATCH.start();numba_getLISTinSET( npLIST, npSetA, npSetB );aStopWATCH.stop()
0
165320L
  7047L
  7328L
  7378L
  7898L
  7519L
  7556L
  7277L
  7296L
  7292L
  7303L
  7302L
  7426L
  7369L
  7307L
>>> setA = generateSet( 1000000 )
>>> len( setA )                                      # the cost of uniqueness
235836
>>> setB = generateSet( 1000000 )

>>> npSetA = np.array( list( setA ), dtype = np.int )
>>> npSetB = np.array( list( setB ), dtype = np.int )

>>> aLIST = list( ( np.random.random( 1000000 * 1.1 + 10 ) * 1000000 * 10000 ).astype( np.int ) )[:1000000]

>>> len( aLIST )
1000000
>>> npLIST = np.array( aLIST, dtype = np.int )

#----------------------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv-------------
#---------------------|                                           |-------------
>>> aStopWATCH.start();numba_getLISTinSET( npLIST, npSetA, npSetB );aStopWATCH.stop()
6
406061L
403946L
409831L
409329L
408920L

#----------------------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv-------------
#---------------------|                                       |-------------
>>> aStopWATCH.start();NathanListPROCESSOR( aLIST, setA, setB );aStopWATCH.stop()
785334
200755L
196791L
195540L
196606L
202483L
197094L
199481L
196651L
200969L
198856L
202039L
200152L
202364L
a = set((1, 3))
b = set((2, 5))
e = 1
e in a # => True
e in b # => False
l = [1, 1, 3, 2, 5, 7, 8, 3, 2, 1]
result = 0 # accumulator for result
for e in l:
  if e in a:
    result += 1
  elif e in b:
    result -= 1

print result # prints "2"