计算 itertools.product() 的第 n 个结果
Calculating the nth result for itertools.product()
我正在尝试计算 itertools.product()
的第 n 个结果
test = list(product('01', repeat=3))
print(test)
desired_output = test[0]
print(desired_output)
所以而不是得到:
[('0', '0', '0'), ('0', '0', '1'), ('0', '1', '0'), ('0', '1', '1'), ('1', '0', '0'), ('1', '0', '1'), ('1', '1', '0'), ('1', '1', '1')]
我正在尝试获取:
('0', '0', '0')
然而,正如您可能已经猜到的那样,它的扩展性并不好。这就是为什么我试图只计算第 n 个值。
我看完了
Nth Combination 但我需要 product() 提供的重复功能
提前致谢!
repeat
功能可以很容易地模拟。这是 this 博客 post 中描述的 Ruby 代码的 python 版本。
def product_nth(lists, num):
res = []
for a in lists:
res.insert(0, a[num % len(a)])
num //= len(a)
return ''.join(res)
调用此函数为
>>> repeats = 50
>>> chars = '01'
>>> product_nth([chars] * repeats, 12345673)
'00000000000000000000000000101111000110000101001001'
这是一些时间测试:
repeat = 50
idx = 112345673
%timeit i = product_nth(['01'] * repeat, idx)
%%timeit
test = product('01', repeat=repeat)
one = islice(test, idx, idx+1)
j = ''.join(next(one))
2.01 s ± 22.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
36.5 µs ± 201 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
print(i == j)
True
另一个答案具有误导性,因为它歪曲了 islice
的功能。例如,参见:
def mygen(r):
i = 0
while i < r:
print("Currently at", i)
yield i
i += 1
list(islice(mygen(1000), 10, 11))
# Currently at 0
# Currently at 1
# Currently at 2
# Currently at 3
# Currently at 4
# Currently at 5
# Currently at 6
# Currently at 7
# Currently at 8
# Currently at 9
# Currently at 10
# Out[1203]: [10]
islice
将逐步执行 每次迭代 ,丢弃结果直到指定的索引。对 product
的输出进行切片时也会发生同样的事情——该解决方案对于大 N 来说效率低下。
如果您构建整个列表,当然不会很好地扩展,因为调用 list()
会贯穿整个迭代器。
如果您只需要第一个值,您可以使用 next(test)
来提取迭代器的第一个值。这不需要构建整个列表并且会非常快。
您还可以使用 itertools.islice()
来获取迭代器的特定部分,而无需构建整个列表,而且速度非常快。但要明白它仍然会迭代到第 N 个值。这是一种非常pythonic的方式来做到这一点,它的内存效率高,而且易于阅读。这是否足够快取决于您的 N 需要多大。例如,这对我来说很快就产生了第 200000 个组合的值:
from itertools import product, islice
test = product('01', repeat=20)
one = islice(test, 200000, 200001)
print(''.join(next(one)))
# 00110000110101000000
我正在尝试计算 itertools.product()
的第 n 个结果test = list(product('01', repeat=3))
print(test)
desired_output = test[0]
print(desired_output)
所以而不是得到:
[('0', '0', '0'), ('0', '0', '1'), ('0', '1', '0'), ('0', '1', '1'), ('1', '0', '0'), ('1', '0', '1'), ('1', '1', '0'), ('1', '1', '1')]
我正在尝试获取:
('0', '0', '0')
然而,正如您可能已经猜到的那样,它的扩展性并不好。这就是为什么我试图只计算第 n 个值。
我看完了 Nth Combination 但我需要 product() 提供的重复功能
提前致谢!
repeat
功能可以很容易地模拟。这是 this 博客 post 中描述的 Ruby 代码的 python 版本。
def product_nth(lists, num):
res = []
for a in lists:
res.insert(0, a[num % len(a)])
num //= len(a)
return ''.join(res)
调用此函数为
>>> repeats = 50
>>> chars = '01'
>>> product_nth([chars] * repeats, 12345673)
'00000000000000000000000000101111000110000101001001'
这是一些时间测试:
repeat = 50
idx = 112345673
%timeit i = product_nth(['01'] * repeat, idx)
%%timeit
test = product('01', repeat=repeat)
one = islice(test, idx, idx+1)
j = ''.join(next(one))
2.01 s ± 22.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
36.5 µs ± 201 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
print(i == j)
True
另一个答案具有误导性,因为它歪曲了 islice
的功能。例如,参见:
def mygen(r):
i = 0
while i < r:
print("Currently at", i)
yield i
i += 1
list(islice(mygen(1000), 10, 11))
# Currently at 0
# Currently at 1
# Currently at 2
# Currently at 3
# Currently at 4
# Currently at 5
# Currently at 6
# Currently at 7
# Currently at 8
# Currently at 9
# Currently at 10
# Out[1203]: [10]
islice
将逐步执行 每次迭代 ,丢弃结果直到指定的索引。对 product
的输出进行切片时也会发生同样的事情——该解决方案对于大 N 来说效率低下。
如果您构建整个列表,当然不会很好地扩展,因为调用 list()
会贯穿整个迭代器。
如果您只需要第一个值,您可以使用 next(test)
来提取迭代器的第一个值。这不需要构建整个列表并且会非常快。
您还可以使用 itertools.islice()
来获取迭代器的特定部分,而无需构建整个列表,而且速度非常快。但要明白它仍然会迭代到第 N 个值。这是一种非常pythonic的方式来做到这一点,它的内存效率高,而且易于阅读。这是否足够快取决于您的 N 需要多大。例如,这对我来说很快就产生了第 200000 个组合的值:
from itertools import product, islice
test = product('01', repeat=20)
one = islice(test, 200000, 200001)
print(''.join(next(one)))
# 00110000110101000000