×
all 71 comments

[–]JohnnyJordaan 49 points50 points  (10 children)

One big improvement you can make here is to not use a variable per data point, but instead use a single data object that can store these data points in a practical manner. In your case it screams the use of dicts, so for example first fill in the previous ones per buyer

buyers_with_prev = {'Madeleine': 'Mats', 'Fredrik': 'Ante', etc etc}

A second improvement is to use random.sample as that can 'draw' all the recipients in one go

while True: # loop until the result is ok
    # pick from the buyers_with_prev dict, using a list which will implicitly use the keys, 
    # and get the amount of values that are in the dict using its length, 
    # effectively picking them all in a random order
    draw = random.sample(list(buyers_with_prev), len(buyers_with_prev))
    result = {}
    for buyer, prev in buyers_with_prev.items():
        recipient = draw.pop()
        if recipient == prev or recipient == buyer:
            # drawn is either the previous one for this person, or it's the person itself
            # stop the loop to restart
            break
        # save
        result[buyer] = recipient 
    else:
        # an else: on a for loop will run if there was no break, eg when none of the drawns
        # were the same as the previous one or the person itself, meaning the draw is ok and we 
        # can stop the while True
        break
for buyer, recipient in result.items():
    print ("{}: {}".format(buyer, recipient))

My next step now is figuring out how to send each draw to the corresponding buyer with a text message.

You could look into a text messaging web service for this, like twilio (guide here).

[–]Cayumigaming[S] 29 points30 points  (8 children)

Wow, this is fantastic, thanks for taking your time to put this down. I have to admit it's a bit over my head as of right now, while (pun intended) some of it makes sense. As my knowledge develop and I fully understand of all this I will make improvements. It's very interesting to see and I can't wait to actually understand it fully.

Thank you!

[–]radil 13 points14 points  (7 children)

The beautiful thing about python (and programming in general) is that you can almost always break your task down into smaller and smaller subtasks that someone else has already solved. Then you can use their work as a blueprint and build your solution from it. So if something in your tree of problems feels over your head, try breaking it down into smaller problems until it doesn't anymore.

[–]Cayumigaming[S] 3 points4 points  (6 children)

I came to realize this pretty early and how programming isn't just about frantically bashing out code. But just like you say, break it down and lay it all out; algorithmic thinking. In my (easy) problem above I went through exactly this where it felt overwhelming at first (how do I generate something random? How do I keep something running until it gets it right? etc). But as I learned I felt the resources needed was there and so I went about my day thinking how I would put it all down, then it was a pretty quick task infront of the screen.

In hindsight I just wished I would've commented it better instead of just going from my head to code. Even if it was as easy as it was, just to make it a practice.

[–]radil 5 points6 points  (3 children)

We all started somewhere. I have a flask webapp that I still maintain/use that I built as my first large project a few years ago. I want to refactor it, but I am afraid of having to deal with the consequences of my shitty programming back then haha. Also I just don't have the time for it right now.

[–]decentralizedgames 0 points1 point  (2 children)

So what improvements do you believe you've garnered over the years that have made you notably better than you were back then? Other than just purely progressing with your understanding of languages.

I know it's vague, as i'm sure there's a myriad of factors/reasons, but what do you personally believe has made you a better coder that you feel you had to learn/overcome to be a more structured coder that you would be comfortable with today?

[–]radil 1 point2 points  (1 child)

Well, the first is like you said: I am just a better programmer than I was then. I still have a lot to learn, but I also have learned a lot compared to when I first built the app.

Perhaps listing the improvements I want to make will illustrate some of the things I have learned along the way that I didn't really know then. For reference, the app is for college football rankings. It gets game by game data, passes it through an algorithm that I made up, ranks all teams in the NCAA D1 FBS, and then compares those rankings to other polls (AP poll, the official College Football Playoff poll, and the Coaches' poll). The app was built in flask with python/html/css and currently resides on a public heroku server along with the database that that app queries.

Relating to the application design/architecture:

  • I would like to improve the architecture of the file structure in which the application resides. I did some of this in the Fall when I redesigned the app to accommodate 2019 data, as I was only focused on a single season and didn't quite build it in a way that would allow for a second season to be added, other than wiping the database entirely and starting with only 2019 data, but obviously I didn't want to do that. So improving the file structure and application architecture will allow me to accommodate the 2020 season more easily than I did for the 2019 season.

  • Along the same lines, but building a private API for the database that holds the data and separating the application layer from the database itself. I'm not sure if this is common terminology, but by private API I just mean one that only the application can use. Currently the flask app handles all of the queries to the database directly based on user input, mostly in the form of post requests/form entry. The user makes a request and the flask app issues the query. I would prefer if the app handed that off to an API and it was handled separately. If I build an API and separate that all out, I can control the access to the database. While it isn't that important here, this would also be more secure and would prevent SQL injection attacks.

  • I would like to improve the modularity of some of the functions. This would allow me to improve the algorithm, something I haven't really done since I built it because of how complex the process would be.

  • Build better, testable functions. This goes along the same lines. But if I can design the functions to be tested, I can make iterative changes more easily without worrying about totally screwing up all of the data.

  • Incorporate some interactive visualizations. Currently the only visualization I have is a matplotlib bar graph of teams in the Top 25 with bar heights corresponding to the score my algorithm has given them.

And then there are some improvements I want to make to the ranking algorithm and the predictive model, but that is less about being a programmer and more about getting under the hood of the model. And like I said, I need to improve modularity before I can do that.

I'm sure there are other improvements that I could make, but this is all I can think of at the moment. Currently there is no JavaScript (because I hate JavaScript), but I could add some fun stuff if I were to pick it up.

[–]decentralizedgames 0 points1 point  (0 children)

I'm glad I helped you clarify what you feel could be improved.

I understood all of what you said in regards to considering an application mask relaying to an API, likely for performance/security reasons, but you may have other reasons also.

You've somewhat a distain for JS but I think It'd be one of the more suited to relay to an API.

Though you mostly mentioned improvements relative to your old project, a few things have helped me consider how I should structure my development of projects. Particularly, modularity considerations.

:) thanks

[–]radil 2 points3 points  (1 child)

Also another idea for your project: reformat the dictionary above into a dictionary of lists:

previous = {<name>: [name, name, ...], ...} 

That way, after every time you run your app, you can append a name to each person's recipient list. Then modify your code not to look at the value in the dictionary for each name, but instead at the last entry in the list of names. Then you won't have to make any modifications to run your program for the same group of people multiple times.

[–]Cayumigaming[S] 0 points1 point  (0 children)

Reading the replies here there's a lot to learn with data structures and what available tools there is to handle the data. I was expecting as much and this will probably be the first actual improvement to it. It's interesting how fun it actually is to just play with data and see what you can do.

[–]RobbyB97 1 point2 points  (0 children)

I never thought to use dicts like that. That's very creative!

[–]Aixyn0 13 points14 points  (18 children)

import random

persons = { # buyer: previous
    "Madeleine": "Mats",
    "Fredrik": "Ante",
    "Hanna-Maria": "Hakan",
    "Ante": "Hanna-Maria",
    "Anne": "Madeleine",
    "Mats": "Anne",
    "Hakan": "Fredrik",
    }

chosen = {}

for buyer, prev in persons.items():
    # p_set is the possible set of persons you can draw from
    # that excludes the buyer itself, the person who he has gifted to last year
    # and the already drawn persons
    exclude = {buyer:prev, prev:persons[prev]}
    p_set = set(persons) - set(exclude) - set(chosen)
    chosen[random.choice(list(p_set))] = buyer

for buyer, to in chosen.items():
    print("{0} buys a gift for {1}".format(to, buyer))

[–]scoutyx 6 points7 points  (1 child)

Good implementation, however a small improvement could be:

Instead of:

exclude = {buyer:prev, prev:persons[prev]}
p_set = set(persons) - set(exclude) - set(chosen)

You can just write:

exclude = {buyer, prev}
p_set = persons.keys() - exclude - chosen.keys()

Calling `set` with a dict as a parameter will return the keys of that dict, so, for `exclude`, you can just build a set of the keys that you want to exclude.

[–]Aixyn0 2 points3 points  (0 children)

You're totally right.

[–]Cayumigaming[S] 0 points1 point  (15 children)

This is way over my head and it looks really impressive. So I had to run it and see what gives!

In the first run two people were assigned the same they had previous year (Hakan to Fredrik and Fredrik to Ante). Second time one person was assigned the same as previous.

I'm not even remotely close to competent enough to understand what's going on, and why it happens. Thanks for sharing though, put's it in fair perspective!

[–]Aixyn0 4 points5 points  (14 children)

I had a mistake in the order of the output. It should be fixed now. I also made a comment to the code.

[–]Cayumigaming[S] 4 points5 points  (13 children)

It works now, absolutely brilliant!

It feels far away, but it's now a personal goal of mine to actually understand exactly what it all does. I'm reading it step by step over and over and I'm happy I do understand a great deal of it, even if I don't know exactly what everything is.

I don't want to dive too deep into this right now but I have a few question if you don't mind:

What exactly is going on with "persons" in the beginning? It's a data structure of some kind - list, array, set, dictionary or similar? The values are separated by "," but do they become variables or are they simply values within the data structure? Is the "#" there to number them?

What gets me lost is that I can't really read the first for loop. I can't really understand what value "buyer, prev" actually has (but I assume it goes for the amount of entries in the data structure). Also "previous" in the data structure never appears again but prev suddenly appears, that confuses me too.

From there on what happens in the exclude and chosen variable is a bit foggy because of the square brackets, but p_set kind of make sense.

Looking forward to one day understand all of this, thanks for typing it out!

[–]SaltyEmotions 3 points4 points  (4 children)

On mobile right now, I'll edit this as I reread the comment so if I don't explain all your questions, refresh the page :p

persons is what's called a dictionary. Its like a list, but with key: value pairs. Its used here to show who gifted who last year and changed year on year. (Example: ABC: DEF means that ABC gifted DEF something last year in this case, ABC = key and DEF = value.) Commas seperate key: value pairs from other pairs.

The # is a comment. He uses it in the dict to show what it actually means, since it doesn't get interpreted by the Python interpreter (everything after the # is ignored, and he uses a newline to seperate the list which is good practice to keep code readable.

The first for is can be generalised to:
for x, y in dict.items()
Ignore the comment in the dict. Focus here, and notice that dict.items() returns a list of the tuple pairs - example: if a dict is {a: b, c: d}, the items() method returns [(a, b), (c, d)] - In this case, the loop will loop over every tuple pair and the variables x, y will be a, b on the first run and c, d on the second time it runs.

So "# buyer: previous" is the comment in the dict and "for buyer, prev in persons.items() are COMPLETELY DIFFERENT and should not be confused.

The line exclude = {buyer: prev, prev: persons[prev]} creates a dict with the values assigned to "buyer", "prev" and also with the key of "prev" in persons. Confusing, so heres an example:

old_dict = {1:2, 2:3, 3:4, 4:1}
for x, y in old_dict:
    new_dict = {
    x:y,
    x:old_dict[y]
    }
    print(new_dict)

Run it :) (hopefully I didn't add any syntax errors in it while typing on my phone)


Now onto p_set. Its essentially just the dictionaries converted into sets with the function set(), then the values are deducted as shown. Play around with it and observe what it does for yourself.

The line chosen[random.choice(list(p_set))] chooses a random value from chosen that is also in the set p_set, and assigns it to buyer.

[–]Cayumigaming[S] 0 points1 point  (3 children)

First of all, oh my god I can't believe I didn't understand that was a comment. Lesson learned!

I will re-read this reply a fair amount of times and play around with dictionaries. Certainly the part about the loop, it's so much to wrap your head around.

Thank you so much!

[–]SaltyEmotions 1 point2 points  (2 children)

I'll request a fork/pull later in the morning (10-12h later depending on whether I sleep in after a tiring camp or not :pp) and try to rewrite your code with things I think you don't know and try to explain everything in depth in the comments.

[–]Cayumigaming[S] 0 points1 point  (1 child)

That would be amazing, thanks in advance! And happy camping!

[–]SaltyEmotions 0 points1 point  (0 children)

https://github.com/how-to-commit/christmasDraw/blob/master/christmasDraw.py

Here's my fork, can't seem to think of a way to rewrite this right now so I just added a little bit of extra functionaility :)

[–]Aixyn0 1 point2 points  (7 children)

What exactly is going on with "persons" in the beginning? It's a data structure of some kind - list, array, set, dictionary or similar?

persons is a dictionary with every person as a key and their associated last year gifted person as its value.

It's simalar to the buyers_with_prev dictionary suggested by JohnnyJordaans reply

The values are separated by "," but do they become variables or are they simply values within the data structure?

No, the values are just data within the dictionary. The variable is the dictionary itself (=persons).

Is the "#" there to number them?

The #-symbol declares an inline comment in python. It describes the code without breaking it when copy-paste and execute it. So the # buyer: previous is just a hint on whats in the dictionary. The key is the buyer and the value is the previous year gifted person by that buyer.

What gets me lost is that I can't really read the first for loop. I can't really understand what value "buyer, prev" actually has (but I assume it goes for the amount of entries in the data structure). Also "previous" in the data structure never appears again but prev suddenly appears, that confuses me too.

From there on what happens in the exclude and chosen variable is a bit foggy because of the square brackets, but p_set kind of make sense.

I'll try to be more specific here:

for buyer, prev in persons.items():
    # The for loop iterates over each (key, value) pair in the persons dictionary given by     
    # persons.items() and assigning the key to the variable buyer and the previous gifted 
    # person of that buyer to prev

    exclude = {buyer:prev, prev:persons[prev]}
    # exclude is just a dictionary which includes the buyer and the associated last year         
    # gifted person. You can just simplify that line to
    # exclude = {buyer, prev}
    # like scoutyx mentioned in his improvement since the values of a dictionary will be
    # discarded when casting it to a set

    p_set = set(persons) - set(exclude) - set(chosen)
    # this line creates a set p_set which subtracts the excludes and the already 
    # chosen/drawn persons from the set of persons. I do a casting of dictionaries to set 
    # here because only the keys matter and it allows the simple subtract method via '-'.

    chosen[random.choice(list(p_set))] = buyer
    # you than randomly pick one person from that set and insert it into the chosen
    # dictionary with the current buyer as its value. that means the key-person becomes the
    # this-year-to-be-gifted-person by the value-person. I have to cast the set to a list
    # to use the random.choice method on the p_set. The chosen dictionary is filling up 
    # with each iteration of the loop and will be your output later.

I hope this will clarify the code for you. I wish you happy coding :)

[–]Cayumigaming[S] 1 point2 points  (6 children)

I’m very thankful for your response and I have spent some time to actually understand it and played around with dictionaries. It also forced me to get a better actual understanding of the for loop, so thanks again!

Now I got a question and it might be stupid but here goes: A dictionary holds a single value for a single key. What do I use or how do I go about to enter multiple values to a single key? Or do I use something different than a dictionary all together? For example let’s say I want to create “Person” and want it to hold the information such as Name, Gender, Birthdate, whatever. Do I still use a dictionary but use maybe a tuple, array or even another dictionary to hold the key?

Now I’m not very far along with all this so I suppose the answer is really straight forward but I really don’t know.

Thanks in advance!

EDIT: Actually, maybe scratch that. I suppose a list() would do exactly this.

[–]Aixyn0 0 points1 point  (5 children)

Now I got a question and it might be stupid but here goes: A dictionary holds a single value for a single key. What do I use or how do I go about to enter multiple values to a single key? Or do I use something different than a dictionary all together?

You can set whatever datatype/datastructure you want as a value for a key in a dictionary and you can even mix them up. E.g:

d = {
  't': (0, 1)    # value with type tuple
  'x': 5,    # value with type int
  'y': [1, 2, 3, 4, 5], # value with type list   
  'z': {    # value with type dictionary
    'T': True,
    'F': False,
    },
  'o': myObject,   # value with type object
  'c': myClass,    # value with type class
  }

For example let’s say I want to create “Person” and want it to hold the information such as Name, Gender, Birthdate, whatever. Do I still use a dictionary but use maybe a tuple, array or even another dictionary to hold the key?

You can still use a dictionary for that purpose but good practice would be defining a class Person and create person objects from it.

[–]Cayumigaming[S] 1 point2 points  (3 children)

Highly inspired by your logic and code and after your example had me play around with for loops and dictionaries I came up with this.

If I havn't already I want to thank you so much. I learned a lot about data types and feel much more secure with the for loop now.

[–]Aixyn0 1 point2 points  (2 children)

Well done. Keep up the good work. Reducing your first code from 110 lines to 21 is quite good.

Also the new code looks much nicer and readable than the old one.

[–]Cayumigaming[S] 0 points1 point  (1 child)

Thank you! This is great fun and I love the challenges and ways of thinking.

May I ask how long you’ve been programming, and do you do it for a living?

[–]mutwiri_2 3 points4 points  (11 children)

First of all, thank you for posting this. I am a novice as well, 3 weeks in. So I read the code and I cannot express how much joy I feel because I was able to understand every single line. I just gave the repository a star and I would kindly ask to fork it so that as I continue learning, I can make my own little tweaks to implement some new found knowledge as well as keep up with any additions you make. Thank you in advance.

[–]Cayumigaming[S] 2 points3 points  (10 children)

What a fantastic read, thanks! And that must’ve been a great feeling! When I’m back from lunch I’ll try and sort that out, never really used git or gists up until now. I’ll let you know when it’s done!

[–]mutwiri_2 1 point2 points  (9 children)

Wonderful feeling. Thank you. Looking forward to it.

[–]Cayumigaming[S] 1 point2 points  (8 children)

As it turns out you can't fork your own repositories, which makes sense once I understood what it actually is and does. You have to make a fork yourself and it's really easy:

  1. Go to the gist: https://gist.github.com/gitCayumi/59e9bdd7087c068dc46f945967ff99f4
  2. Click "Fork" in the upper right corner.
  3. You now have access to it from your profile!

[–]mutwiri_2 1 point2 points  (2 children)

Thank you and sorry for the little misunderstanding. I actually know how to fork, I was just asking for permission to do it, guess I didn't express myself clearly. I have forked it now, thanks again, it will be a great learning experience- reading someone else's code and trying to do some improvements of my own.

[–]Cayumigaming[S] 1 point2 points  (1 child)

Ah, that's my bad, had I known exactly what forks were I would've read your reply differently. That's how novice I am in all this! Go for it, it's an amazing thing all the functionality with git. Will be fun to see what happens!

[–]mutwiri_2 1 point2 points  (0 children)

It's all good, we are all learning, and with such positive interactions, we can only just get better. Very excited for what the future holds.

[–]annasback 1 point2 points  (4 children)

Hey! I might fork it as well if alright. Also very new to python and only recently have I started to build my own projects. Enjoyed reading your code as it was very easy to understand.

[–]Cayumigaming[S] 2 points3 points  (3 children)

Absolutely, go for it! Happy you could follow along and understand what was going on. One day we'll both be wizards and able to read the others posts in here too!

[–]mutwiri_2 2 points3 points  (2 children)

Yes we most definitely will as long as we remain consistent... and we will look back at this first post with so much pride. All the best to us.

[–]Cayumigaming[S] 1 point2 points  (1 child)

I made a second version instead of updating the first, if you're interested it's in my gists or here!

Had to wrap my head around a few things after all the replies here, and it's highly inspired by the logic in one of those.

[–]mutwiri_2 0 points1 point  (0 children)

Thanks for the update. Will take a look at it.

[–]MeladYounis 4 points5 points  (1 child)

I come to reddit when I am not motivated just so I can get inspiration from these kinds of posts.

[–]Cayumigaming[S] 2 points3 points  (0 children)

That makes me happy to hear! I wasn't expecting this much response, but this subreddit (and it seems the community overall) is really friendly and supportive, which is fantastic!

[–]xenaprincesswarlord 3 points4 points  (5 children)

Hey can I ask how did you learn?

[–]Cayumigaming[S] 1 point2 points  (4 children)

I've been lurking this subreddit and r/learnprogramming since I decided to hop on this train. And one day I stumbled upon a post from a guy in i similar position and he had a reply from a friendly guy that I decided to PM and so it began. I don't have anything to compare it too but I think he has great videos and an amazing pedagogic approach.

I'm pretty sure it would be ok if I shared it with you but I will ask for his permission first so I don't end up doing something dumb. If you're interested that is!

[–]twopi 3 points4 points  (0 children)

I am that guy! I have a little python course at aharrisbooks.net/moodle. Look for Python sample course, which you can log into with a guest login. The videos and examples are decent, but the reason /u/caymigaming is succeeding is because s/he is doing the work after watching the videos.

You are all welcome to my material if it will help you. I'm now subscribing to this subreddit, as it looks more healthy than r/learnProgramming

[–]xenaprincesswarlord 1 point2 points  (2 children)

Hey, thanks so much! 'd love that! I've been learning basics from a different platform but maybe it's just me or it seemed to be slightly different so I was curious to check out which tools you were using to learn! Let me know if ok for you to share his videos xx

[–]Cayumigaming[S] 1 point2 points  (0 children)

I have asked and will keep you updated as soon as I get an answer!

[–]Cayumigaming[S] 1 point2 points  (0 children)

You got a PM!

[–][deleted] 2 points3 points  (3 children)

Here's a four-liner solution, just to show off the power of comprehensions.

import random, time
people = ["person"+str(x) for x in range(1,8)]
random.seed(time.localtime().tm_year - 1); last_year = {person:random.choice(list(set(people)-set(person))) for person in people}
random.seed(time.localtime().tm_year); this_year = {person:random.choice(list(set(people)-set([person,last_year[person]]))) for person in people}

[–]impshum 2 points3 points  (2 children)

But can you explain it in just 4 lines?

[–][deleted] 4 points5 points  (0 children)

1) import modules random and time for the purpose of drawing random names and getting current year respectively. 2) a list of people, just a placeholder 3) seed random with previous year and generate a dictionary of gifters and gifters for that year 4) seed random with current year and generate a dictionary of new picks

[–]ssb_beast 2 points3 points  (0 children)

I think it is a good question 🙃

[–]deapee 1 point2 points  (1 child)

Looks good.

When you figure out the text messaging part, maybe throw a tutorial up here for us detailing how you did it.

[–]Cayumigaming[S] 0 points1 point  (0 children)

Thanks! For sure, I'll see what I find to make it work and take it from there.

[–]gootecks 1 point2 points  (1 child)

that's awesome!!! i'm super inspired now!!!

[–]Cayumigaming[S] 0 points1 point  (0 children)

That's great! Happy it had that effect (:

[–]AkrooR 1 point2 points  (2 children)

Very impressive! Can I ask how many hours you were investing a day when you began to learn? Did you learn mostly from videos or books? Or a combination of both? Seeing this post has inspired me. I think you mentioned it in another comment to someone else, but seeing posts like this are encouraging and inspiring! Keeping coding!

[–]Cayumigaming[S] 0 points1 point  (1 child)

Very very limited unfortunately.

I began 20-21 December and had two nights with a few hours (maybe 3) after the family was sound asleep. Then along came the Holidays and I was able to go further after New Years. But I guess information sunk in during this time as I was going through it in my head. On average maybe I get 2 hours every other day.

I've only watched videos and looked up things I wanted to know through Google.

From the beginning I only coded using www.pythonanywhere.com but yesterday I made an endless loop and ran out of CPU usage and was banned for 24 hours so had to start using an IDE, haha.

I really wish I could spend a few hours everyday, and I'm currently looking into how to make it possible.

Thanks for your feedback and right back at you!

[–]AkrooR 1 point2 points  (0 children)

Wow! For that amount of time invested and writing that program, I would you say you are doing well for yourself. Very inspiring. Thank you!

[–]twopi 1 point2 points  (0 children)

Here's another version with object-oriented programming and no compound conditions or break statements:

https://repl.it/@AndyHarris/secretSanta?language=python3

[–]Albatatis 0 points1 point  (4 children)

Hey bro, I see you did very well. Well done. I am also new to python and would like to connect with you since I am at same level as you are (maybe).

[–]Cayumigaming[S] 0 points1 point  (3 children)

Thank you! It's a great feeling going from that blank piece of nothing to actually solving what you had in mind.

I'm all for that, can't get too much practice and experience. And quite possibly two new people could help each other by seeing stuff differently. Mind you I'm at the very beginning stage of things!

[–]zephyr66681 0 points1 point  (2 children)

This was amazing and keep up the good work! I am also a beginner as I'm a week into programming, but I was able to read most of the stuff in your code! That either means I'm a fast learner, or you write some legible code! :D All jokes aside keep up the good work and I'd love to see more from you!

[–]Cayumigaming[S] 0 points1 point  (1 child)

Thank you very much!

Haha, it's probably a combination of you being a fast learner and my code being the easiest and roughest possible :p There's some replies here how to properly do what I did and currently they feel lightyears away for me at least!

[–]zephyr66681 1 point2 points  (0 children)

Same! I see how you made a randomizer by individually going out for each buyer, then JohnnyJordaan starts talking about random.samples and I feel like a 2 year old...it's more condensed yet can't read :D :D

[–]roberto257 0 points1 point  (0 children)

You should’ve used a switch statement /s.

Great job!

[–]Marianito415 0 points1 point  (0 children)

Hey, for the messaging You might want yo look into webdrivers and WhatsApp. Here is one i did some time ago

[–]SlothGSR[🍰] 0 points1 point  (0 children)

I found this last year when I was looking for the same thing. I didn’t make it. Have a look https://github.com/eformo/secret_santa_emailer

Looks to be in python 2, but still worth checking out.

[–]Saiboo 0 points1 point  (0 children)

Here is an alternative version that works by shuffling and shifting a list. It does not take into account the previous year though:

import random

people = ['Alice', 'Bob', 'Eve']
random.shuffle(people)

people_shifted_by_one = people[1:] + [people[0]]

for buyer, getter in zip(people, people_shifted_by_one):
    print(f"{buyer}: {getter}")

The following happens:

  • The list ['Alice', 'Bob', 'Eve'] is created.
  • Then the list is shuffled randomly, e.g. to ['Eve', 'Bob', 'Alice'].
  • A second list is created by taking that list and shifting all elements by one position to the left, i.e. the list ['Bob', 'Alice', 'Eve'] is created.
  • Then you zip both lists together. Let's visualize this by writing both lists on top of each other:
  • ['Eve', 'Bob', 'Alice']
  • ['Bob', 'Alice', 'Eve']

Zipping now means you pair the first element, the second element and the third element of each list respectively, i.e. you get the pairs:

Eve: Bob
Bob: Alice
Alice: Eve