Python - list.remove(x) x not in list

3
我正在尝试创建一个简单的Python 3.3程序,它接受四个名称的列表,并将它们随机分配给列表中的其他人。例如,如果姓名是John、Aaron、Lydia和Robin:
John先选出一个名字。他不能抽到自己的名字,如果他抽到了,就把它放回去再抽一次。假设John抽到了Robin的名字。Robin的名字将从池中消失。接下来轮到Aaron抽签,他抽到了John。John的名字被淘汰了。等等,直到所有的名字都被分配完。
我创建了一个包含四个名字的列表,并为每个名字分配了1-4的值。然而,在移除列表时遇到了问题,显示值不存在。 list.remove(x):x不在列表中。
代码大致如下所示:
def drawNames():
    import random
    John=1
    Aaron=2
    Lydia=3
    Robin=4
    validNames=[John, Aaron, Lydia, Robin]
    nameDrawn=random.choice(validNames)
    def draw():
        nameDrawn=random.choice(validNames)
    #John's Draw:
    draw()
    if nameDrawn != 1:
        if nameDrawn == 2:
            print("John drew: Aaron")
            validNames.remove(2)
        elif nameDrawn == 3:
            print("John drew: Lydia")
            validNames.remove(3)
        elif nameDrawn == 4:
            print("John drew: Robin")
            validNames.remove(4)
    #Aaron's Draw:
    draw()
    if nameDrawn !=2:
        if nameDrawn ==1:
            print("Aaron drew: John")
            validNames.remove(1)
        elif nameDrawn ==3:
            print("Aaron drew: Lydia")
            validNames.remove(3)
        elif nameDrawn ==4:
            print("Aaron drew: Robin")
            validNames.remove(4)
    #Lydia's Draw:
    draw()
    if nameDrawn !=3:
        if nameDrawn ==1:
            print("Lydia drew: John")
            validNames.remove(1)
        elif nameDrawn ==2:
            print("Lydia drew: Aaron")
            validNames.remove(2)
        elif nameDrawn ==4:
            print("Lydia drew: Robin")
            validNames.remove(4)
    #Robin's Draw:
    draw()
    if nameDrawn !=4:
        if nameDrawn ==1:
            print("Robin drew: John")
            validNames.remove(1)
        elif nameDrawn ==2:
            print("Robin drew: Aaron")
            validNames.remove(2)
        elif nameDrawn ==3:
            print("Robin drew: Lydia")
            validNames.remove(3)
drawNames()

我也尝试使用名称而不是数字值,但仍然出现了相同的错误。

我认为这种方案效率低下。如果您有更好的建议,我将非常感激。


相关问题 - dansalmo
这类似于“白象礼物交换”或“秘密圣诞老人”抽签吗?您是否想防止两个人互相挑选? - dansalmo
6个回答

2
你可以使用以下代码来获得更好的效果; 它比你提供的代码更适用于多个名称的扩展。
import copy
import random
validNames=["John", "Aaron", "Lydia", "Robin"]

def drawNames(namelist,currentname):
    '''
    namelist: list of names to draw from
    currentname: name of person doing the current draw
    '''
    draw_namelist = copy.copy(namelist) # make a copy to remove person drawing if needed
    if currentname in draw_namelist: # check if the person drawing is in the list
        draw_namelist.remove(currentname) # remove current name if in list
    try:
        drawn_name = random.choice(draw_namelist)
        namelist.remove(drawn_name)
        newnamelist = namelist
        print "Drew {}".format(drawn_name)
        print "New list: {}".format(newnamelist)
    except:
        print "Nobody for me to draw!"
        drawn_name=None
        newnamelist = namelist
    return drawn_name, newnamelist

这可以按照以下方式运作:
In [39]: newlist=["John", "Aaron", "Lydia", "Robin"]

In [40]: name,newlist = drawNames(newlist,"Lydia")
Drew Robin
New list: ['John', 'Aaron', 'Lydia']

In [41]: name,newlist = drawNames(newlist,"John")
Drew Aaron
New list: ['John', 'Lydia']

In [42]: name,newlist = drawNames(newlist,"Aaron")
Drew John
New list: ['Lydia']

In [43]: name,newlist = drawNames(newlist,"Robin")
Drew Lydia
New list: []

那样要高效得多。我会尝试的。 - CharlieTango92
如何让代码在用户未输入自己姓名的情况下运行?我尝试在if语句中添加一个条件。我将你的random.choice函数改到定义之前,并添加了nameChoice=random.choice(namelist)这一行代码。然后我在下面附加了一个if语句:if currentname in namelist and currentname!=nameChoice。但是,我收到了无效语法的错误提示。 - CharlieTango92
嗨,抱歉我最初错过了那个!我已经更新了我的答案,现在应该可以正常工作并且更加健壮 :) - qmorgan
将此代码更改为Python 3.3后,它工作得非常好!效率提高了许多。谢谢! - CharlieTango92

1

你需要调用实际元素,而不是在remove中使用索引。将数字替换为人名列表中实际存在的名称,代码应该按预期工作。


谢谢您的回复。但是正如我在问题中所述,当我执行类似于“validNames.remove(Robin)”这样的操作时,它仍然会抛出“x不在列表中”的错误。 - CharlieTango92
哦,我错过了,抱歉。 - user6993

0
请注意,如果列表长度为奇数,则存在潜在的无限循环。
import random
from copy import copy
def f(name):
    x = random.choice(validNames)
    while x == name:
        x = random.choice(validNames)
    else:
        validNames.remove(x)
    return (name, x)

print map(f, copy(validNames))

>>> [('John', 'Robin'), ('Aaron', 'John'), ('Lydia', 'Aaron'), ('Robin', 'Lydia')]

0

你肯定是用了一种较为困难的方法。

与其反复查找列表并删除值,不如打乱列表并读取成对的值,像这样:

from random import shuffle

def random_pairs(lst):
    shuffle(lst)
    return zip(lst[::2], lst[1::2])

def main():
    names = 'John,Aaron,Lydia,Robin'.split(',')
    print random_pairs(names)

if __name__=="__main__":
    main()

这只是将人们分成一组。我认为他希望每个人都拥有另一个人的名字,就像“秘密圣诞老人”抽签一样。虽然可能会分组,但在名字较多的情况下不太可能。 - dansalmo

0
>>> from random import shuffle
>>> valid_names=["John", "Aaron", "Lydia", "Robin"]
>>> shuffle(valid_names)
>>> for pair in zip(valid_names, (valid_names*2)[1:]):
...     print(pair)
...
('Aaron', 'John')
('John', 'Lydia')
('Lydia', 'Robin')
('Robin', 'Aaron')

0
最简单的方法就是随机洗牌名字并将每个名字分配给下一个人。这还可以保证两个人不会互相拥有对方的名字。
>>> from random import shuffle
>>> names=['John', 'Aaron', 'Lydia', 'Robin']
>>> shuffle(names)
>>> dict(zip(names, names[-1:] + names))
{'Aaron': 'Lydia', 'John': 'Robin', 'Lydia': 'John', 'Robin': 'Aaron'}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接