递归发生了太多次,并且列表不可迭代

时间:2018-09-12 15:59:30

标签: python-3.x

我正在尝试制作一个秘密的圣诞老人程序。输入形式为人物g的姓名。 [“ John”,“ Bob”,“ Alice”]和emial列表[“ John@gmail.com”,“ Bob@gmail.com”,“ Alice@outlook.com”]。我需要生成成对的电子邮件地址和一个不属于上述电子邮件地址的随机名称。为此,我编写了功能比较。

def compare(list_of_names, list_of_emails):
    zipped_lists = zip(list_of_emails, list_of_names)
    random.shuffle(list_of_emails)
    zipped_shuffled_lists = zip(list_of_emails, list_of_names)
    for pair in zipped_lists:
        for shuffle_pair in zipped_shuffled_lists:
            if shuffle_pair == pair:
                return compare(list_of_names, list_of_emails)
    return zipped_shuffled_lists

但是它不会像这样拖曳,而是会创建递归。我仍然不知道为什么。在有限的时间后,它应该创建两个有效的不同列表。另外shuffled_list_of_emails也无法迭代,为什么?

编辑:更改了代码的顺序,因为它可以在原处工作

2 个答案:

答案 0 :(得分:1)

zip很懒!

我不确定为什么,但是我对此感到非常兴奋,因此答案可能有点混乱。随时要求澄清)


让我们逐步完成代码:

def compare(list_of_names, list_of_emails):
    # the `zip` object doesn't actually iterate over any of its arguments until you attempt to iterate over `zipped_lists`
    zipped_lists = zip(list_of_emails, list_of_names)

    # modify this IN-PLACE; but the `zip` object above has a pointer to this SAME list
    random.shuffle(list_of_emails)

    # since the very first `zip` object has `list_of_emails` as its argument, AND SO DOES THE ONE BELOW, they both point to the very same, SHUFFLED (!) list
    zipped_shuffled_lists = zip(list_of_emails, list_of_names)

    # now you're iterating over identical `zip` objects
    for pair in zipped_lists:
        for shuffle_pair in zipped_shuffled_lists:

            # obviously, this is always true
            if shuffle_pair == pair:

                # say "hello" to infinite recursion, then!
                return compare(list_of_names, list_of_emails)
    return zipped_shuffled_lists

让我们在Python解释器中重新创建它!

>>> List = list(range(5))
>>> List
[0, 1, 2, 3, 4]
>>> zipped_1 = zip(List, range(5))
>>> import random
>>> random.shuffle(List)
>>> zipped_2 = zip(List, range(5))
>>> print(List)
[4, 2, 3, 0, 1]
>>> zipped_1, zipped_2 = list(zipped_1), list(zipped_2)
>>> zipped_1 == zipped_2
True

您会看到,两个不同的zip对象在不同的​​时间应用于同一列表(在修改列表之前和之后),它们产生的结果完全相同!由于zip一旦执行zip(a, b)后就不会进行压缩,因此在您运行时,它会产生压缩的……呃,东西……即时正在遍历它!

因此,要解决此问题,请不要混洗原始列表,也不要混洗其副本:

list_of_emails_copy = list_of_emails.copy()
random.shuffle(list_of_emails_copy)
zipped_shuffled_lists = zip(list_of_emails_copy, list_of_names)

答案 1 :(得分:0)

@ForceBru已经提供了正确的答案。但是a会有所贡献。
您应该避免zip's lazy 评估,并使用list展开zip:

def compare(list_of_names, list_of_emails):
    zipped_lists = list(zip(list_of_emails, list_of_names))  # eager evaluation instead of lazy
    random.shuffle(list_of_emails)  # shuffle lists
    zipped_shuffled_lists = list(zip(list_of_emails, list_of_names))  # eager again
    for pair in zipped_lists:
        for shuffle_pair in zipped_shuffled_lists:
            if shuffle_pair == pair:
                return compare(list_of_names, list_of_emails)
    return zipped_shuffled_lists

但是我想您不需要递归并且可以更轻松地完成任务:

def compare(list_of_names, list_of_emails):
    zipped_lists = list(zip(list_of_emails, list_of_names))
    random.shuffle(zipped_lists)  # shuffle list of emails and names
    result = []
    shuffled_emails = [i[0] for i in zipped_lists]
    for i, _ in enumerate(shuffled_emails):
        result.append(zipped_lists[i-1][1])  # shift email relatively one position to the right
    return list(zip(result, shuffled_emails))

此代码将名称与以前选择的电子邮件链接,该电子邮件是随机选择的,并且保证不匹配。 没有递归,对于具有两个或多个元素的列表非常有用。