3

I am trying to create a simple program in Python 3.3 that takes a list of four names, and randomly assigns them to another person in the list. For example, if the names were John, Aaron, Lydia, and Robin:

John goes first and selects a name. He cannot draw his own; if he does, he puts it back and draws again. Say John drew Robin's name. Robin's name would be eliminated from the pool. Next is Aaron's turn to draw. He draws John. John's name is eliminated. etc. until all names are assigned.

I created a list with four names and assigned each one a value 1-4. However, i'm running into an issue when removing from a list, saying the value does not exist.

list.remove(x) : x not in list.

it looks something like this:

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()

i've also tried using the names rather than the numeric values, which yielded the same error.

I also feel like this is an inefficient scheme. If you have a better suggestion I'd be much obliged.

CharlieTango92
  • 169
  • 1
  • 2
  • 10
  • [related question](http://stackoverflow.com/questions/15096157/how-to-shuffle-an-array-so-that-all-elements-change-their-place) – dansalmo Dec 07 '13 at 02:29
  • Is this like a "White elephant" or "Secret Santa" drawing? Would you like to prevent two people from picking each other? – dansalmo Dec 07 '13 at 03:10

6 Answers6

2

You might have better mileage with a code like this below; it's more scalable to many names than what you've provided above.

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

This can then work as follows:

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: []
qmorgan
  • 4,794
  • 2
  • 19
  • 14
  • that's a heck of a lot more efficient. I'll try that. – CharlieTango92 Dec 07 '13 at 02:34
  • how Do i make this account for someone not drawing their own name? I tried to add something onto that if statement. i changed your random.choice to further up before the definition and said nameChoice=random.choice(namelist) and then later down added on your if statement if currentname in namelist and currentname!=nameChoice: but i'm given invalid syntax. – CharlieTango92 Dec 07 '13 at 02:47
  • Hi Sorry I missed that initially! I've updated my answer and it should be working and more robust :) – qmorgan Dec 07 '13 at 02:52
  • thank you! after changing this to Python 3.3 it works wonderfully! Much more efficient. – CharlieTango92 Dec 07 '13 at 04:02
1

You have to call the actual element, not the index in remove. Replace the numbers with the actual names of people as they exist in the list, and the code should work as intended.

user6993
  • 41
  • 3
0

note that there is a potential infinite loop in case the list len is an odd number

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')]
Guy Gavriely
  • 11,228
  • 6
  • 27
  • 42
0

The simplest of all is to just shuffle the names and assign each to the next. It also guarantees that two people will not have each other names.

>>> 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'}
dansalmo
  • 11,506
  • 5
  • 58
  • 53
0

You are definitely doing it the hard way.

Instead of repeatedly seeking into the list and removing values, just shuffle the list and read off pairs, like so:

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()
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
  • This just pairs people up. I think he wants every person to have someone else's name like in a "Secret Santa" drawing. Paring could happen, but it is not very likely with a larger number of names. – dansalmo Dec 07 '13 at 03:07
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')
John La Rooy
  • 295,403
  • 53
  • 369
  • 502