我需要创建一个递归函数(为简单起见),它接受任何嵌套列表并返回一组唯一元素。
为了解决这个问题,我决定首先创建一个获取列表并将其转换为集合的函数:
ranList = [2, 2, 4, 5, 3, 1, 3]
def eue(ranList):
newList = set(ranList)
return print(newList)
很简单,它有效。现在创建一个函数,它接受一个嵌套列表并返回一个二维列表(这是我在这个站点上使用搜索找到的递归函数)和一个接受另一个函数的函数,并返回一个包含唯一元素的集合: p>
lis = [['c', 'd'], 2, 2, 4, 5, 3, 1, 3, ['c']]
from collections import Iterable
def flatten(lis):
for item in lis:
if isinstance(item, Iterable) and not isinstance(item, str):
for x in flatten(item):
yield x
else:
yield item
def eue(lis):
newSet = set(flatten(lis))
print(newSet)
现在,通过调用eue(),它解决了我原来的问题。但我想让它变得更加简单化。
如何组合这些函数来生成单个函数,以减少运行所需的计算时间?
感谢。
答案 0 :(得分:1)
您可以使用itertools.chain
将所有迭代器链接在一起:
from itertools import chain
from collections import Iterable
def isIter(obj):
return isinstance(obj, Iterable) and not isinstance(obj,str)
def flatten(it):
seqs = (flatten(item) if isIter(item) else (item,) for item in it)
return chain(*seqs)
def enu1(it):
return set(gen(it))
虽然这意味着对于每个非序列元素,您必须使用该项(item,)
创建元组以使链正常工作,但不确定它对性能的影响有多大。
您可以通过转换为集合将其减少为单个函数(isIter
除外):
def enu2_A(it):
seqs = (enu2_A(item) if isIter(item) else (item,) for item in it)
return set(chain(*seqs))
但是这又为set
的每次递归调用创建了一个新的enu
对象,可能会添加一个转换选项吗?
def enu2(it,return_set = True):
seqs = (enu2(item,False) if isIter(item) else (item,) for item in it)
if return_set:
return set(chain(*seqs))
else:
return chain(*seqs)
但将它组合成一个单独的功能实际上并没有提供太多的速度提升:
import timeit
a = timeit.timeit("enu1(lis)","from __main__ import enu1,lis",number=10000)
b = timeit.timeit("enu2(lis)","from __main__ import enu2,lis",number=10000)
print(a,b)
print(a/b) #ratio, more then 1 means a took longer
输出:
0.3400449920009123 0.32908301999850664
1.0333106582115827
通过组合成一个单独的功能,快3%,我猜这不是你期望的速度,你的代码是非常有效的,因为它是更加pythonesque然后我的所以我不会改变它
编辑:刚刚对我的enu2
和你的enu
进行了基准测试 - 你的方法比我提供的方法快了大约16%,请保留它是因为你不能变得更好,然后转移到python2并使用compiler.ast.flatten
或另一个C级等效:
from collections import Iterable
def flatten(lis):
for item in lis:
if isinstance(item, Iterable) and not isinstance(item, str):
for x in flatten(item):
yield x
else:
yield item
def enu(obj):
return set(flatten(obj))
lis = [['c', 'd'], 2, 2, 4, 5, 3, 1, 3, ['c']]
import timeit
a = timeit.timeit("enu(lis)","from __main__ import enu,lis",number=10000)
b = timeit.timeit("set(ast.flatten(lis))","from __main__ import lis ; from compiler import ast",number=10000)
print(a,b)
print(a/b)
输出:
0.3324121500045294 0.28561264199379366
1.1638565705076622
所以在C中执行操作加快了4X的过程,但是根据the docs,compiler
包已经过时了2.6:
从2.6版开始不推荐使用:Python 3中已删除了编译器包。
所以很有可能如果你在C扩展中编写flatten
你可以获得更好的结果,但是如果你想用纯python编写代码,那么你可以获得尽可能好的代码。