Cython:具有 2 个列表的简单函数,最快的方法是什么?
Cython: simple function with 2 lists, what is the fastest way?
我想做的 - 将我的纯 Python 代码转换为 Cython。
纯Python代码:
def conflicts(list1,list2):
numIt = 10
for i in list1:
for j in list2:
if i == j and i < numIt:
return True
return False
conflicts([1,2,3], [6,9,8])
到目前为止我的 Cython 代码:
cdef char conflicts(int [] list1,int [] list2):
cdef int numIt = 10
for i in list1:
for j in list2:
if i == j and i < numIt:
return True
return False
conflicts([1,2,3], [6,9,8])
由于我是 Cython 的新手(在 Python 方面并不是真正的专家),所以我想获得一些关于我的转换的反馈。我做对了吗?为了使功能更快,我还应该做些什么吗?
更新:
有谁知道如何在输入(list1、list2)函数的 header 中添加类型?我尝试了 "int [:]" 编译没有错误但是当我尝试用两个列表调用函数时我得到消息 "TypeError: 'list' does not have the buffer interface"。
可以声明 "i" 和 "j" 以优化您的代码。使用 cython 的第一次优化是使用显式声明完成的。
您可以使用
cython -a yourcode.py
并查看一些可能更改的自动建议,以使用 cython(黄线)优化您的 python 代码。您可以使用生成的 c 模块(工作完美!)。
部分手写cython优化:
+ 对 list1 和 list2 使用类型 list。
+ bint type for conflicts functions because that return boolean value.
+ 获取列表的长度,因为 for 循环需要结束索引。
+ 在 int 数组中映射列表(因为列表只有整数值)。
cdef bint conflicts(list list1, list list2):
cdef int numIt = 10
cdef int i, j
cdef int end_index = len(list1)
cdef int[:] my_list1 = list1
cdef int[:] my_list2 = list2
for i in range(end_index):
for j in range(end_index):
if my_list1[i] == my_list2[j] and my_list1[i] < numIt:
return True
return False
conflicts([1,2,3], [6,9,8])
正如我评论的那样,您应该能够通过更改算法获得相当大的改进,而根本不会弄乱 cython。您当前的代码是 O(len(list1)*len(list2))
,但您可以使用 set
将其缩减为 O(len(list1)+len(list2))
。您还可以使用内置的 any
函数来简化代码:
def conflicts(list1,list2):
numIt = 10
s1 = set(list1)
return any(x in s1 and x < numIt for x in list2)
根据每个列表中您希望小于 10 的数字的数量,您可以尝试稍微移动 x < numIt
测试以查看最快的(在您转向之前过滤 list1
例如,将其放入 set
,或者在 any
内的生成器表达式中将 if x < numIt
放在 for
之后。
我想做的 - 将我的纯 Python 代码转换为 Cython。
纯Python代码:
def conflicts(list1,list2):
numIt = 10
for i in list1:
for j in list2:
if i == j and i < numIt:
return True
return False
conflicts([1,2,3], [6,9,8])
到目前为止我的 Cython 代码:
cdef char conflicts(int [] list1,int [] list2):
cdef int numIt = 10
for i in list1:
for j in list2:
if i == j and i < numIt:
return True
return False
conflicts([1,2,3], [6,9,8])
由于我是 Cython 的新手(在 Python 方面并不是真正的专家),所以我想获得一些关于我的转换的反馈。我做对了吗?为了使功能更快,我还应该做些什么吗?
更新:
有谁知道如何在输入(list1、list2)函数的 header 中添加类型?我尝试了 "int [:]" 编译没有错误但是当我尝试用两个列表调用函数时我得到消息 "TypeError: 'list' does not have the buffer interface"。
"i" 和 "j" 以优化您的代码。使用 cython 的第一次优化是使用显式声明完成的。
您可以使用
cython -a yourcode.py
并查看一些可能更改的自动建议,以使用 cython(黄线)优化您的 python 代码。您可以使用生成的 c 模块(工作完美!)。
部分手写cython优化:
+ 对 list1 和 list2 使用类型 list。
+ bint type for conflicts functions because that return boolean value.
+ 获取列表的长度,因为 for 循环需要结束索引。
+ 在 int 数组中映射列表(因为列表只有整数值)。
cdef bint conflicts(list list1, list list2):
cdef int numIt = 10
cdef int i, j
cdef int end_index = len(list1)
cdef int[:] my_list1 = list1
cdef int[:] my_list2 = list2
for i in range(end_index):
for j in range(end_index):
if my_list1[i] == my_list2[j] and my_list1[i] < numIt:
return True
return False
conflicts([1,2,3], [6,9,8])
正如我评论的那样,您应该能够通过更改算法获得相当大的改进,而根本不会弄乱 cython。您当前的代码是 O(len(list1)*len(list2))
,但您可以使用 set
将其缩减为 O(len(list1)+len(list2))
。您还可以使用内置的 any
函数来简化代码:
def conflicts(list1,list2):
numIt = 10
s1 = set(list1)
return any(x in s1 and x < numIt for x in list2)
根据每个列表中您希望小于 10 的数字的数量,您可以尝试稍微移动 x < numIt
测试以查看最快的(在您转向之前过滤 list1
例如,将其放入 set
,或者在 any
内的生成器表达式中将 if x < numIt
放在 for
之后。