有一个相关的问题here。我正在尝试在HackerRank上进行this项目欧拉挑战。它需要的是您能够导出字符串“ abcdefghijklm”的第 n 个排列。有13个!排列。
我尝试了一个使用for num, stry in zip(range(1, math.factorial(13)), itertools.permutations("abcdefghijklm"):
的简单解决方案。可行,但超时。
最好的做法是将每个值存储在dict
中,然后执行以下操作:
import itertools
import math
strt = "abcdefghijklm"
dic = {}
perms_gen = itertools.permutations(strt)
idxs_gen = range(1, math.factorial(13))
curr_idx = 0
test_list = [1, 2, 5, 10]
def get_elems(n):
for num, stry in zip(idxs_gen, perms_gen):
print(num) # debug
str_stry = "".join(stry)
dic[num] = str_stry
if num == n:
return str_stry
for x in test_list:
if curr_idx < x:
print(get_elems(x))
else:
print(dic[x])
这不起作用。我得到以下输出:
1
abcdefghijklm
1
2
abcdefghijlkm
1
2
3
4
5
abcdefghikjml
1
2
3
4
5
6
7
8
9
10
abcdefghilmkj
在我写这个问题时,我显然找到了答案……继续。
答案 0 :(得分:2)
暂停是生成器的内置功能。这是发电机的一半。但是,range
不是生成器。这是一个惰性序列类型。
如果希望对象在其上进行再次迭代将在上次停止的位置继续进行,则需要对范围对象进行迭代:
idsx_iter = iter(range(1, math.factorial(13)))
但是,保存zip
迭代器而不是两个基础迭代器会更简单。更好的是,使用enumerate
:
indexed_permutations = enumerate(itertools.permutations(strt))
不过,您还有很多在代码中没有意义的东西,例如curr_idx
永远保持为0,或者range
界限可以产生13! -1个索引而不是13个!索引,实际上,您应该使用更有效的算法。例如,一个方法是通过将下一个元素设置为特定字符,然后直接计算每个元素来确定您跳过了多少个排列。
答案 1 :(得分:0)
确定您可以消耗迭代器it
的一部分,只需调用next(it)
即可消耗一个项目。或者,如果您需要一次消耗多个,则可以编写一个函数来消耗迭代器中的n
个项目。在这两种情况下,您只需要注意迭代器尚未结束(引发StopIteration
)即可:
def consume(iterator, n):
for i in range(n):
try:
yield next(iterator)
except StopIteration:
return
然后可以这样使用:
>>> r = iter(range(5))
>>> print(list(consume(r, 3)))
[0, 1, 2]
>>> print(list(consume(r, 3)))
[3, 4]
最后,我不明白为什么您需要针对这个特定问题使用它,并且如建议的那样,有一个Python函数itertools.permutations
已经为您迭代了所有排列。
答案 2 :(得分:-2)
标题中问题的答案为“是”,您可以暂停并重新启动。怎么样?
(对我来说)意外地zip()
会重新启动压缩生成器,尽管先前已对其进行了定义(也许有人可以告诉我为什么会这样?)。因此,我添加了main_gen = zip(idxs_gen, perms_gen)
并从for num, stry in zip(idxs_gen, perms_gen):
更改为for num, stry in main_gen:
。然后,我得到以下输出,假设字符串正确,则正是我想要的:
1
abcdefghijklm
2
abcdefghijkml
3
4
5
abcdefghijmkl
6
7
8
9
10
abcdefghiklmj
更改后,代码如下:
import itertools
import math
strt = "abcdefghijklm"
dic = {}
perms_gen = itertools.permutations(strt)
idxs_gen = range(1, math.factorial(13))
main_gen = zip(idxs_gen, perms_gen)
curr_idx = 0
test_list = [1, 2, 5, 10]
def get_elems(n):
for num, stry in main_gen:
print(num)
str_stry = "".join(stry)
dic[num] = str_stry
if num == n:
return str_stry
for x in test_list:
if curr_idx < x:
print(get_elems(x))
else:
print(dic[x])