3

I'm trying to make a Secret Santa program. Ideally the program should ask for at least three names, and afterwards the program asks if there are more names. If yes, open up another text field and add it to the list of names. If no, break the loop, create a separate list with the names inside it, shuffle the second list of names, and pair them up with a name from the original list.

For example, if John, Elliot, Sarah and Jenny put in their names and the program shuffled their names, it should output something like this:

[('John', 'Sarah'), ('Elliot', 'John'), ('Sarah', 'Jenny'), ('Jenny', 'Elliot')]

But instead I get something like:

[('John', 'John'), ('Elliot', 'John'), ('Sarah', 'Elliot'), ('Jenny', 'Jenny')]

Here's the code:

import sys
import random

names = []

class Santa:
    #The class that takes the values, shuffles them, pairs and then displays them
    def __init__(self, name):
        self.turns = name
        self.people = names
        self.final = []

    def sort_names(self):
        random.shuffle(self.people)
        for name in self.turns:
            pair = (name, random.choice(self.people))
            if pair[0] == [1]:
                pair = (name, random.choice(self.people))

            else:
                self.final.append(pair)

    def print_name(self):
        input("\nNames are ready! Press Enter to show the names.")
        print(self.final)

def main():
    # The function asking for user input
    name = input("\nType in your name. ")
    names.append(name)
    name = input("\nType in the next name. ")
    names.append(name)
    name = input("\nType in the next name. ")
    names.append(name)
    while True:
        next = input("\nIs this everyone? Y/N ")
        if next.upper() == "Y":
            break
        elif next.upper() == "N":
            name = input("\nType in the next name. ")
            names.insert(0, name)
        else:
            print("\nInvalid response, please try again.")
    print(names)
    start = Santa(names)
    start.sort_names()
    start.print_name()
    input("\nRecord these, and press enter to quit.")
    sys.exit()

main()
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • Is there a typo in __init__()? You seem to set ```self.turns``` to ```name``` instead of ```names``` – cischa Dec 07 '19 at 19:49
  • I just tried it. I changed the `self.turns` reference and declaration inside the `__init__()` properties to `names'. Not much seems to have changed. – CScience416 Dec 07 '19 at 19:57
  • 2
    Looks overly complicated. If `names` is a list with the shuffled names you can create your pairs like this: `pairs = [(name1, name2) for name1, name2 in zip(names, names[1:] + [names[0]])]` – Matthias Dec 07 '19 at 20:01
  • 1
    @Matthias `zip()` already returns tuples so `list(zip(names, names[1:] + [names[0]]))` would already be enough. – Darkonaut Dec 07 '19 at 21:35
  • 1
    Oh yes. It was an `OutOfCoffeeError`. – Matthias Dec 07 '19 at 22:27

2 Answers2

2

You shouldn't need an entire class to set this up, and I have tried to clean up a little of reading input.

import random


names = []
for _ in range(3):
  name = input("\nType in your name. ")
  names.append(name)

while True:
  next = input("\nIs this everyone? Y/N ")
  if next.upper() == "Y":
    break
  elif next.upper() == "N":
    name = input("\nType in the next name. ")
    names.insert(0, name)
  else:
      print("\nInvalid response, please try again.")
print(names)

random.shuffle(names)
pairs = [(first_person, second_person) for first_person, second_person in zip(names, names[1:] + [names[0]])]
print(pairs)
Spencer Stream
  • 616
  • 2
  • 6
  • 22
1

Your problem is the comparison so you do not draw yourself:

    for name in self.turns:
        pair = (name, random.choice(self.people)) 

        # you compare against [1] ? That is a list containing a 1 as only thing 
        # and it will never be True unless if you compare string vs. name
        if pair[0] == [1]:
            pair = (name, random.choice(self.people)) 
        else:
            self.final.append(pair)

You can streamline your loop and you have to handle odd/even number of names when pairing people up. Using list slicing and zipping makes it easier to pair up people.

Example:

import sys
import random
 
class Santa: 
    def __init__(self, names): 
        self.people = names 

    def shuffle(self):
        random.shuffle(self.people)

        self.final = []

        if len(self.people) < 2:
            print("Sorry, not enough people to gift stuff around")
            return

         # taken from the comment, because superior to what I had originally
         # see edit history for my solution ;o) - this one suggested by @Matthias
         self.final = [(n1, n2) for n1, n2 in zip(names, names[1:] + [names[0]])]
 
    def print_name(self): 
        print(self.final)


name = "dummy"
names = []
while name:
    name = input(f"Whats the {len(names)+1}. name? (Empty to end) ").strip()
    if not name:
        break
    names.append(name)
print(names)
santa = Santa(names)
santa.shuffle()
santa.print_name() 

Output (omitted input outputs):

# odd inputs
['Tim', 'John', 'Luise', 'Maria', 'Wasja']
[('Wasja', 'Maria'), ('Maria', 'John'), ('Luise', 'Tim')]

['Tim', 'John', 'Luise', 'Maria', 'Wasja']
[('Maria', 'Wasja'), ('Wasja', 'Tim'), ('John', 'Luise')]

# even inputs
['Tim', 'John', 'Luise', 'Maria']
[('John', 'Tim'), ('Maria', 'Luise')]

['Tim', 'John', 'Luise', 'Maria']
[('Luise', 'Tim'), ('John', 'Maria')]

You can read more about zip and list slicing here:

Community
  • 1
  • 1
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69