【问题标题】:python list generation/saving bugpython列表生成/保存错误
【发布时间】:2014-01-21 18:10:31
【问题描述】:

我正在尝试制作打印azzz 的所有可能组合的程序。我尝试添加一个保存状态功能,它工作正常,但有这个错误。

假设我在打印e 之类的内容时中断了程序。当我再次执行该程序时,它在z 之前工作正常,但在z 之后而不是打印aa 它打印ba 并从ba 继续。这也发生在它打印zz 之后。它打印baa 而不是aaa。我该如何解决这个问题?

这是我到目前为止所做的:

 import pickle,os,time

 alphabet="abcdefghijklmnopqrstuvwxyz"
 try:
     if os.path.isfile("save.pickle")==True:
         with open("save.pickle","rb") as f:
             tryn=pickle.load(f)
         for i in range(3):
             a=[x for x in alphabet]
             for j in range(i):
                 a=[x+i for x in alphabet for i in a]
             b=a[tryn:]
             for k in b:
                 print(k)
                 time.sleep(0.01)
                 tryn+=1
     else:
         tryn=0
         for i in range(3):
             a=[x for x in alphabet]
             for j in range(i):
                 a=[x+i for x in alphabet for i in a]
             for k in a:
                 print(k)
                 tryn+=1
                 time.sleep(0.01)
 except KeyboardInterrupt:
     with open("save.pickle","wb") as f:
         pickle.dump(tryn,f)

【问题讨论】:

  • 使用更深的缩进。 4 个空格是推荐的大小。这很难阅读。

标签: python list python-3.x combinations


【解决方案1】:

如果您使用 python2 或标签建议的 python3,则它已经存在于标准库中。请参阅 itertools、product py2product py3,了解解决此问题的简单方法。

【讨论】:

  • permutations 是错误的函数。 product 就是你要找的。​​span>
  • +1 处理裸代码很有趣,但我们应该永远记住,标准库有很多需要榨取的汁液。
  • 啊,是的,如果您想要重复的字符,正如您明确表示的那样,这就是您想要的功能。有了这个,你仍然需要一个循环来增加返回组合的所需长度。
【解决方案2】:
  for i in range(3):
   a=[x for x in alphabet]
   for j in range(i):
    a=[x+i for x in alphabet for i in a]
   b=a[tryn:]

这是你的错误。您跳过每个长度的第一个 tryn 字符串,而不仅仅是第一个 tryn 字符串。如果不是以下情况,这将更容易在输出中识别:

   for k in b:
    print(k)
    time.sleep(0.01)
    tryn+=1

你修改tryn,你跳过的东西的数量。当您打印出长度为 2 的字符串时,您会跳过与长度为 1 的字符串数量相等的数量。当您打印出长度为 3 的字符串时,您会跳过与长度为 2 的字符串数量相等的数量。如果 tryn 大于长度为 1 的字符串的数量,你会跳过更多。

【讨论】:

  • 我认为这不是问题,因为输出总是相同的:“ba”,即使我在 OR z 处中断。不过如果你真的认为这是问题所在,你能给我一些提示吗?
  • @user3220419:答案的后半部分对此进行了解释。至于提示,请跳过完整序列的第一个tryn。您可以通过构建一个包含所有字符串的大列表然后对其进行切片来做到这一点。
【解决方案3】:

你的问题几乎肯定在这里:

a=[x for x in alphabet]
for j in range(i):
    a=[x+i for x in alphabet for i in a]

也许您不应该将循环内的值分配给 a,而是使用不同的名称?否则,您每次都在通过循环更改您使用的内容....

编辑:更多细节。因此,从技术上讲,user2357112 的答案更正确,但我正在修改我的答案。最初的答案只是快速阅读,所以另一个答案接近原意。但是,原始版本效率低下(原因多于不使用 product :),因为您不止一次生成内部循环。那么让我们来看看为什么这是一个坏主意,作为一个教育练习:

初始算法:

for i in range(n):
    assign a to alphabet
    for j in range(i): 
        i times, we rewrite a to be all combinations of the current set against the alphabet.

注意,对于这个算法,要生成 length(n) 乘积,我们必须生成所有之前的乘积 length(n-1), length(n-2), ..., length(1)。但你没有保存那些。

你最好做这样的事情:

sum_list = alphabet[:]
#get a copy
product_list = alphabet[:]
#Are we starting at 0, or 1? In any case, skip the first, since we preloaded it
for i in range(1, n):
    # Your existing list comprehension was equivalent here, and could still be used
    # it MIGHT be faster to do '%s%s'%(x,y) instead of x+y... but maybe not
    # with these short strings
    # This comprehension takes the result of the last iteration, and makes the next iteration
    product_list = [x+y for x,y in product(product_list, alphabet)]
    # So product list is JUST the list for range (n) - i.e. if we are on loop 2, this
    # is aaa...zzz. But you want all lengths together. So, as you go, add these
    # sublists to a main list.
    sum_list.extend(product_list)

总的来说,你做的工作少了很多。

结合其他的东西:

  • 您将 i 用作循环变量,然后在循环理解中重新使用它。这是相互矛盾的,并且可能无法按您预期的方式工作。
  • 如果这是为了学习如何编写保存/恢复类型的应用程序......这不是一个好方法。请注意,restore 函数正在重新计算每个值,以便能够回到它停止的位置 - 如果您可以重写此算法以将更多信息写入文件(例如 product_list 的当前值)并使其更像生成器,那么它实际上会更像一个真实的例子。

【讨论】:

  • 你能给我举个例子吗?我实际上已经尝试过了,但它总是说它没有定义,即使它定义了
  • 实际上,现在我已经看多了,我想我明白你在做什么了。尝试用a.extend([x+i for x... 替换a=[x+i for x...,看看是否有帮助。
  • 它有效,科利!谢谢!你能解释一下这是做什么的吗?
  • @user3220419:该修改并没有按照您的想法进行。它碰巧引入了一个可以部分抵消您现有错误的错误;您仍然每次都跳过第一个 tryn 字符串,但现在列表在您要打印的内容之前前面有 tryn 垃圾元素。还有问题;我相信你会经历两次长度为 2 的字符串。
  • 是的,我认为它仍然不是很正确......看起来这是一种求和的递归循环。作为练习很好。请注意,它还使用 i 作为循环变量 (for i in range(3)) 以及列表理解中,这是冲突的。但是,为了解释算法,我将添加一些细节。
【解决方案4】:

以下是我建议在 Python 中解决此问题的方法。我没有实现保存状态功能;这个序列不是很长,你的计算机应该能够很快地产生这个序列,所以我认为尝试让它完全可中断是不值得的。

import itertools as it

def seq(alphabet, length):
    for c in range(1, length+1):
        for p in it.product(alphabet, repeat=c):
            yield ''.join(p)

alphabet="abcdefghijklmnopqrstuvwxyz"

for x in seq(alphabet, 3):
    print(x)

如果你真的想,你可以使用itertools 制作一个单行字。我认为这太难阅读和理解了;我更喜欢上面的版本。但由于使用了itertools.chainitertools.imap() 而不是Python for 循环,这确实有效并且会更快一些。

import itertools as it

def seq(alphabet, length):
    return it.imap(''.join, it.chain.from_iterable(it.product(alphabet, repeat=c) for c in range(1, length+1)))

alphabet="abcdefghijklmnopqrstuvwxyz"

for x in seq(alphabet, 3):
    print(x)

在 Python 3.x 中,您可以只使用 map() 而不是 itertools.imap()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-08
    相关资源
    最近更新 更多