Python 高效地创建生成器以按顺序输出数字列表
我想创建一个输出递增数字列表的生成器。 前 我可以用蛮力的方式来实现这一点(不完全正确,但在这个应用程序中并不重要,因为它有两个0): 侧面图Python 高效地创建生成器以按顺序输出数字列表,python,python-3.x,Python,Python 3.x,我想创建一个输出递增数字列表的生成器。 前 我可以用蛮力的方式来实现这一点(不完全正确,但在这个应用程序中并不重要,因为它有两个0): 侧面图 Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 56.083 56.083 part2_extended.py:1(<module
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 56.083 56.083 part2_extended.py:1(<module>)
100000000 14.221 0.000 14.221 0.000 part2_extended.py:1(isGrowing)
1278 0.001 0.000 0.004 0.000 part2_extended.py:17(meetsAdjacentCriteria)
100000000 13.181 0.000 27.452 0.000 part2_extended.py:25(isValid)
1278 0.002 0.000 0.003 0.000 part2_extended.py:28(findAdjacents)
100000001 9.726 0.000 10.689 0.000 part2_extended.py:81(generateNumbersStupid)
24310 0.031 0.000 0.046 0.000 part2_extended.py:9(inRange)
1 17.942 17.942 56.083 56.083 part2_extended.py:92(calculateCount)
1 0.000 0.000 56.083 56.083 part2_extended.py:99(main)
6630 0.000 0.000 0.000 0.000 {len}
9524 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
194480 0.016 0.000 0.016 0.000 {pow}
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 49.618 49.618 part2_extended.py:1(<module>)
46191900 6.844 0.000 6.844 0.000 part2_extended.py:1(isGrowing)
1278 0.001 0.000 0.004 0.000 part2_extended.py:17(meetsAdjacentCriteria)
46191900 6.827 0.000 13.677 0.000 part2_extended.py:25(isValid)
1278 0.002 0.000 0.003 0.000 part2_extended.py:28(findAdjacents)
46191901 18.352 0.000 26.127 0.000 part2_extended.py:43(generateNumbersArray2)
1278 0.002 0.000 0.003 0.000 part2_extended.py:9(inRange)
1 9.814 9.814 49.618 49.618 part2_extended.py:92(calculateCount)
1 0.000 0.000 49.618 49.618 part2_extended.py:99(main)
46198530 1.865 0.000 1.865 0.000 {len}
9524 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
10224 0.001 0.000 0.001 0.000 {pow}
但这要慢得多
def generateNumbersArrayInPlace(startNumber, endNumber):
start = [int(x) for x in str(startNumber-1)]
for num in range(startNumber, endNumber):
lastIndex = len(start) - 1
start[lastIndex] = start[lastIndex] + 1
for digit in range(lastIndex, -1, -1):
if start[digit] > 9:
start[digit] = 0
if digit == 0:
start.insert(0,1)
else:
start[digit-1] = start[digit-1] + 1
else:
break
yield start[:]
还尝试过清洁剂:
def generateNumbersArray(startNumber, endNumber):
for num in range(startNumber, endNumber+1):
yield [int(x) for x in str(num)]
它的速度也要慢得多
def generateNumbersArrayInPlace(startNumber, endNumber):
start = [int(x) for x in str(startNumber-1)]
for num in range(startNumber, endNumber):
lastIndex = len(start) - 1
start[lastIndex] = start[lastIndex] + 1
for digit in range(lastIndex, -1, -1):
if start[digit] > 9:
start[digit] = 0
if digit == 0:
start.insert(0,1)
else:
start[digit-1] = start[digit-1] + 1
else:
break
yield start[:]
如果我尝试将所有内容保持在适当的位置,而不生成新的阵列,它会大大加快速度,但仍然会显著降低速度
def generateNumbersArrayInPlace(startNumber, endNumber):
start = [int(x) for x in str(startNumber-1)]
for num in range(startNumber, endNumber):
lastIndex = len(start) - 1
start[lastIndex] = start[lastIndex] + 1
for digit in range(lastIndex, -1, -1):
if start[digit] > 9:
start[digit] = 0
if digit == 0:
start.insert(0,1)
else:
start[digit-1] = start[digit-1] + 1
else:
break
yield start[:]
侧面图
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 56.083 56.083 part2_extended.py:1(<module>)
100000000 14.221 0.000 14.221 0.000 part2_extended.py:1(isGrowing)
1278 0.001 0.000 0.004 0.000 part2_extended.py:17(meetsAdjacentCriteria)
100000000 13.181 0.000 27.452 0.000 part2_extended.py:25(isValid)
1278 0.002 0.000 0.003 0.000 part2_extended.py:28(findAdjacents)
100000001 9.726 0.000 10.689 0.000 part2_extended.py:81(generateNumbersStupid)
24310 0.031 0.000 0.046 0.000 part2_extended.py:9(inRange)
1 17.942 17.942 56.083 56.083 part2_extended.py:92(calculateCount)
1 0.000 0.000 56.083 56.083 part2_extended.py:99(main)
6630 0.000 0.000 0.000 0.000 {len}
9524 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
194480 0.016 0.000 0.016 0.000 {pow}
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 49.618 49.618 part2_extended.py:1(<module>)
46191900 6.844 0.000 6.844 0.000 part2_extended.py:1(isGrowing)
1278 0.001 0.000 0.004 0.000 part2_extended.py:17(meetsAdjacentCriteria)
46191900 6.827 0.000 13.677 0.000 part2_extended.py:25(isValid)
1278 0.002 0.000 0.003 0.000 part2_extended.py:28(findAdjacents)
46191901 18.352 0.000 26.127 0.000 part2_extended.py:43(generateNumbersArray2)
1278 0.002 0.000 0.003 0.000 part2_extended.py:9(inRange)
1 9.814 9.814 49.618 49.618 part2_extended.py:92(calculateCount)
1 0.000 0.000 49.618 49.618 part2_extended.py:99(main)
46198530 1.865 0.000 1.865 0.000 {len}
9524 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
10224 0.001 0.000 0.001 0.000 {pow}
简介:
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 90.430 90.430 part2_extended.py:1(<module>)
100000000 14.977 0.000 14.977 0.000 part2_extended.py:1(isGrowing)
1 0.000 0.000 90.430 90.430 part2_extended.py:101(main)
1278 0.001 0.000 0.004 0.000 part2_extended.py:17(meetsAdjacentCriteria)
100000000 14.289 0.000 29.317 0.000 part2_extended.py:25(isValid)
1278 0.002 0.000 0.003 0.000 part2_extended.py:28(findAdjacents)
100000001 34.681 0.000 40.798 0.000 part2_extended.py:62(generateNumbersItertools)
24310 0.032 0.000 0.048 0.000 part2_extended.py:9(inRange)
1 20.315 20.315 90.430 90.430 part2_extended.py:94(calculateCount)
6630 0.000 0.000 0.000 0.000 {len}
9524 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
100000001 6.116 0.000 6.116 0.000 {next}
194480 0.016 0.000 0.016 0.000 {pow}
ncalls tottime percall cumtime percall文件名:lineno(函数)
1 0.000 0.000 90.430 90.430部分2_扩展。py:1()
100000000 14.977 0.000 14.977 0.000第2部分扩展。py:1(正在增长)
1 0.000 0.000 90.430 90.430零件2_加长件:101(主)
1278 0.001 0.000 0.004 0.000零件2_扩展。py:17(满足相邻标准)
100000000 14.289 0.000 29.317 0.000第2部分扩展。py:25(有效)
1278 0.002 0.000 0.003 0.000零件2_扩展。py:28(FindAjacents)
100000001 34.681 0.000 40.798 0.000零件2_扩展。py:62(GenerateNumberSiteTools)
24310 0.032 0.000 0.048 0.000零件2_扩展。py:9(范围内)
1 20.315 20.315 90.430 90.430零件2_扩展py:94(计算计数)
6630 0.000 0.000 0.000 0.000{len}
9524 0.001 0.000 0.001 0.000{“列表”对象的“附加”方法}
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
100000001 6.116 0.000 6.116 0.000{next}
194480 0.016 0.000 0.016 0.000{pow}
也非常慢。我自己运行了一些测试,将您的“愚蠢”函数
generateNumberStudy()
与使用itertools.product()
的函数进行比较,正如评论所说,它更快
对于以下每个函数,我都运行了10次试验,并计算了平均时间(请记住,我在执行期间遍历了函数返回的生成器中的所有元素):
愚蠢的功能
def generateNumbersStupid():
for x1 in range(10):
for x2 in range(10):
for x3 in range(10):
for x4 in range(10):
for x5 in range(10):
for x6 in range(10):
for x7 in range(10):
for x8 in range(10):
yield [x1,x2,x3,x4,x5,x6,x7,x8]
平均时间:16.513799535秒
itertools.product()生成器
def generateNumbersItertools():
return product(range(10), repeat=8)
平均时间:3.82409999371秒
它按照您最初的愿望清理代码,并且执行速度更快。在这种情况下,我看不到使用
生成器的必要性,特别是考虑到返回和遍历列表的速度要快得多。我自己做了一些测试,将您的“愚蠢”函数GenerateNumberStudy()
与使用itertools.product()
的函数进行比较,正如评论所说,它更快
对于以下每个函数,我都运行了10次试验,并计算了平均时间(请记住,我在执行期间遍历了函数返回的生成器中的所有元素):
愚蠢的功能
def generateNumbersStupid():
for x1 in range(10):
for x2 in range(10):
for x3 in range(10):
for x4 in range(10):
for x5 in range(10):
for x6 in range(10):
for x7 in range(10):
for x8 in range(10):
yield [x1,x2,x3,x4,x5,x6,x7,x8]
平均时间:16.513799535秒
itertools.product()生成器
def generateNumbersItertools():
return product(range(10), repeat=8)
平均时间:3.82409999371秒
它按照您最初的愿望清理代码,并且执行速度更快。在这种情况下,看不到使用生成器的必要性,特别是考虑到返回和遍历列表的速度要快得多。不运行配置文件,仅使用timeit
我就看到了巨大的改进,通过使用itertools.product
并将其与itertools.dropwhile相结合,您的前导列表中不再有前面的零,尽管第一个输出将是一个空列表。这与您期望的输出最接近:
generateNumbers = (list(dropwhile((0).__eq__, p)) for p in product(range(10), repeat=8))
这导致:
[]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[1, 0]
[1, 1]
[1, 2]
[1, 3]
[1, 4]
[1, 5]
[1, 6]
[1, 7]
...
没有运行配置文件,仅使用timeit
我就看到了巨大的改进,通过使用itertools.product
并将其与itertools.dropwhile相结合,您的前导列表中不再有前面的零,尽管第一个输出将是一个空列表。这与您期望的输出最接近:
generateNumbers = (list(dropwhile((0).__eq__, p)) for p in product(range(10), repeat=8))
这导致:
[]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[1, 0]
[1, 1]
[1, 2]
[1, 3]
[1, 4]
[1, 5]
[1, 6]
[1, 7]
...
下面是一个递归生成器,它根据您的要求提供指定长度的序列:
def f(length):
if length == 1:
for i in range(1,10):
yield [i]
else:
for ls in (x for x in f(length-1)):
for i in range(10):
yield ls + [i]
因此,您可以以任意长度调用它<代码>[x代表范围(1,3)内的i,x代表f(i)]
将导致:
[[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8],
[9],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4],
...
如果您正在寻找发电机:
for item in (x for i in range(1, some_number) for x in f(i)):
#do stuff
下面是一个递归生成器,它根据您的要求提供指定长度的序列:
def f(length):
if length == 1:
for i in range(1,10):
yield [i]
else:
for ls in (x for x in f(length-1)):
for i in range(10):
yield ls + [i]
因此,您可以以任意长度调用它<代码>[x代表范围(1,3)内的i,x代表f(i)]
将导致:
[[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8],
[9],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4],
...
如果您正在寻找发电机:
for item in (x for i in range(1, some_number) for x in f(i)):
#do stuff
不确定是否有比上一种更快的方法,但为什么您首先需要这种方法?生成器不是免费的,如果您使用一个简单的for
循环替换使用此生成器的代码,您可以获得更好的性能。创建此类内容的最简单方法是从itertools导入组合与替换
@politinsa组合与替换
生成固定长度随后。@Selcuk当我看到第二个版本的速度有多慢时,了解发生了什么就成了一个学术问题。但是把线圈从发电机里移开会快一点。很高兴听到。如果/当您需要可变性时,如何在调用方中强制转换列表?这肯定比while:True、嵌套迭代器和list comp hijinks快得多。在产品(范围(10,重复=8))中的x尝试:列表(x)
。我敢打赌这是相当合理的。不确定是否有比上一个更快的方法,但为什么你首先需要这个?生成器不是免费的,如果您将使用此生成器的代码替换为简单的for
循环,您可以获得更好的性能。创建此类内容的最简单方法是使用