Random name picker

June 26, 2021

The idea of this Python project comes from who gets to go first or what order do a group of people go in. Think of kids getting ready to play a game and need to decide who goes first and what order they go in. They might do something like pull a card from a deck or roll a die to figure out who goes first. With these methods you can get arguments like, ‘they didn’t shake the die enough’ or ‘it hit something’ or ‘they didn’t pull far enough in the deck’. This program is to have it randomly pick the name and order from a list of names. This could be useful in assigning what order kids would play the game or the order to do a certain choir.

For this program I created a group of people: Jane, Sally, Tim, George, Phil, Ann; these will be the ones used to test the program. The simplest way to do this program would be to put the names into a list and run random.sample on them and get a list of the names in a random order. However, when I did that to the group, it showed Ann for the first 5 times I ran it. With it being the same each time I thought this would be a bad sign and also make for a really short and boring post and we can’t have that, so I made it bigger and better. Also kids would think you’re cheating so adding some numbers beside the names to show that the results change each time.

To make it that there would be changes every time this ran, I would have it run random several time and add to each name when their name is chosen. After that it would then need to be sorted with the highest number first and print the list of the names along with the number of time random selected them. That was the basic premises of the new program, a bit of feature creep showed up there. Feature creep is where you have a program figured out then other requests start getting added, usually causing more work and sometimes rewriting of other features to get them included. Don’t worry by the time we get to the end of this program more feature creep will show up.

To start off on this program I need to import the random library.

import random

Next, I need to bring in our contestants, the ones you’ve met earlier:

names = ['Jane', 'Sally', 'Tim', 'George', 'Phil', 'Ann']

The line: I created a list and named it ‘names’ because I’m clever with my naming? No, you want to name objects in your program to be easy for you to remember and also for anybody else that is working on the program to easily understand it. If this was for a game show other good names would be contestants or players.

To be able to add numbers to the names I need to convert the list of ‘names’ to a library. The reasons I didn’t start with a library for the names is to keep it easier to read and update; if in the future I want to make the names a user input it can be easily setup. I’m also going to need this as a list later; so it’s just better to keep this first line as a list.

names_dictionary = dict.fromkeys(names, 0)

The line: what this is doing is creating a names_dictionary, the dict.fromkeys is telling the program that we’re creating the dictionary from something and using that as the key. In the () I need to add the key, then he value for the key. We’re putting the ‘names’ list in the first part for it to be the key, then the 0 (zero) in the second part this will be the value to each key. Making all the names have a value of 0 to start. Keys have to be unique values so you can’t have 2 Ann’s in the list, plus it would be very confusing to know which one. You can have a ‘Sally’ and a ‘Sallie’ as these are 2 different names.

Now that we have something that we can add numbers too for each name we’ll need to run the random several times and then each time add one to the person selected.

count = 0
while count < 1001:
    name = random.choice(names)
    names_dictionary[name] += 1
    count +=1

First line: creating a variable called ‘count’ to have an item to add up as we go through the numbers. This is for the program do know how many times it ran this will not go to the players.

Second line: While loop checking the ‘count’ variable to make sure it’s still under 1001, you can go with any number here you want, if really small you might have a lot of duplicate numbers.

Third line: creating a variable ‘name’ then assigning to it the name that is randomly chosen from the call to random. The ‘.choice’ is telling random to choose 1 from the list that is passed in (). In this case the ‘names’ that we created originally. Another way to read this: we are choosing a ‘name’ from ‘names’.

Fourth line: this is looking into the dictionary called ‘names_dictionary’ to find the key named with what was picked in the ‘name’ variable we just created. Then it will add 1 to the value’s total. The += is saying take the total that is there and add 1 to it. If we did = 1, it would assign 1 to it each time causing it after the 1001 random runs everybody that had random pick at least once would end up with a value of just 1.

Fifth line: taking the variable ‘count’ and adding one to the total, just like we did previously with the name, if we didn’t add to this each time we would get an infinity loop since the while loop would never hit 1001. Another way to read this: this is adding up each time random runs, so after 1001 times it will know to stop.

At this point we have a library with the names and their totals, if you did a print statement here, you would get something like this:

{‘Jane’: 168, ‘Sally’: 162, ‘Tim’: 186, ‘George’: 144, ‘Phil’: 176, ‘Ann’: 165}

As you keep running it those numbers would keep changing. You’ll also notice that the names are listed in the same order as we created the ‘names’ list.

Feature creep:

At this point I had created the sorting feature but in testing I seen at times there would be a tie. I needed a way to break the tie. After going through some ideas; even did one idea where it would create a tie breaker area at the bottom of the list where it would break the ties and if you tied you would need to look at bottom, this was way to clunky to be useful. This tie breaker needed to be added before we sort the list for easier reading.

To work around this issue, I went back and added (using some of the same code from the tie breaker area) to add a calculation based on the position in a list of the names selected.

We’ll continue with this new feature.

This area we’re looking through the dictionary for any duplicate values and putting them into a new dictionary by the value number.

result = {}
for val in names_dictionary:
    if names_dictionary[val] in result:
        result[names_dictionary[val]].append(val)
    else:
        result[names_dictionary[val]] = [val]

First line: creating a new variable ‘result’ and making it an empty library.

Second line: for loop going through the ‘names_dictionary’ item by item assigning each item as ‘val’ as it goes through.

Third line: checking if the ‘val’ in ‘names_dictionary’ is a key in ‘result’, if the number is already there then will execute in the next line. If not it will go to the ‘else:’ statement.

Fourth line: if it is then we’re going to append (add to) ‘results’ the name of the person to that matching value.

Fifth & sixth lines: Else statement, meaning if the if statement isn’t true then do this. If the value wasn’t already in ‘results’ then this will add the value and the person. Such as Jane had 500 it would create a 500: Jane.

I changed the program to run random 10 times to help show what this is doing, this is how ‘result’ looks in a run of the program:

{1: [‘Jane’, ‘Ann’], 2: [‘Sally’, ‘Phil’], 4: [‘Tim’], 0: [‘George’]}

We’ll use the ‘1’ key. First, we have the results created then Jane goes through the system, it goes to the else and creates a key of ‘1’ and assigns her name to it. Then when Ann goes through the system, it sees that 1 is already created and then assigns Ann to the value of the 1 key with Jane.

Now that we have the duplicates into a library we will need to randomize the duplicates. If we don’t then it will stay in the same order as our original list. To make it fair we have to run another random over these names, this time we’ll use the method that was originally mentioned of random.sample on the value. We didn’t do it before because it could show the same person winning several times. This time we have the random running 1001 times before that keeps changing the values.

for key in result:
    ties = list(result[key])

First line: we’re going through each element in ‘result’ assigning it as ‘key’

Second line: creating a variable ‘ties’ and assigning it a list that is converted from the values of names. Such as in one pass through of key: ties =  [‘Jane’, ‘Ann’].

Still inside that for loop for ‘key’; checks if each number has more than one person

       if len(ties) > 1:
        nameNum = len(names)
        if len(names) < 100:
                divBy = 100
        else:
            divBy = 1000
        tieBreaker = random.sample(ties, len(ties))
        for tie in tieBreaker:
            indexPlace = tieBreaker.index(tie)
            # print('first',tie, index, 'TB', tieBreaker)
            names_dictionary[tie] += (nameNum-indexPlace)/divBy
            # print(names_dictionary)

First line: checks if there is more than one name in the ‘ties’ variable, len is short for length. For the sample above ties has a length of 2 (Jane and Ann). If there is only one name in there we don’t need to run random.

Second Line: creating a variable called ‘nameNum’ it will be grabbing the length of the names list, this will be used later.

Third – Sixth line: If statement checking if the length of names is less than or more than 100, if this would be for a big group or organization and they put in a lot of names, while the chance of duplicates being over 100 is very small we’re quickly checking for it, if under 100 we assign 100 if over, we assign 1000. If we didn’t do this and there was over 100 people tie, the person in first place would get a +1 and could take them up a level and now tie with somebody else and we don’t want that.

Seventh line: creating a new variable ‘tieBreaker’ and assigning it the random function of sample, sample is saying I want random for a set number of positions. Inside the () we’re telling it to run random on ‘ties’ and for the length (len) of ties so it will return everybody in ‘ties’ in a random order.

Eighth line: for loop assigning ‘tie’ to the elements in ‘names_dictionary’ then going through one item at a time.

Ninth line: creating a variable called ‘indexPlace’ and assigning to it the index number of ‘tie’; such as 1. Inside the ‘tieBreaker’ list. A list uses a zero based system, in [‘Jane’, ‘Ann’] Jane is in position 0; Ann in position 1.

Tenth line: it’s going out to ‘names_dictionary’ with the key (the person’s name) and then += adding the results to what is currently out there the equation of ‘nameNum’ the one where we got how many people are in the list minus the position (‘indexPlace’) then take that total and divide by the ‘divBy’ which will either be 100 or 1000. This way nobody in the tie list should have the same fraction number added to their total.

Now that we have our contestants with numbers and there should be no duplicates we can now sort the list and print the dictionary to the screen.

sort_winners = sorted(names_dictionary.items(), key=lambda x: x[1], reverse=True)

The line: we’re creating a new variable ‘sort_winners’ and assigning to it a sorted list using the items in ‘names_dictonary’ by the keys (names). Then using a lambda, a lambda is a way to use a function inside a function, telling it to sort by the values. Finally telling the sort to reverse the sort by saying ‘reverse=True’. A normal sort will sort by the key (names) and in ascending order (1, 2, 3). With this we’re sorting the number by descending order.

A final outcome could look like this (taken from a real test):

George 178

Jane 172.06

Sally 172.05

Ann 161.06

Tim 161.05

Phil 157

When you add up all the whole numbers you get 1001. The items to the right of the decimal where added by the tie breaker element.

Link to Git Project

Full code:

import random
  
# initializing list 
names = ['Jane', 'Sally', 'Tim', 'George', 'Phil', 'Ann']

#Creates dictionary from the name and assigns 0 to them
names_dictionary = dict.fromkeys(names, 0)
count = 0

#while loop to go to 100 get the random count
while count < 1001:
    name = random.choice(names)
    names_dictionary[name] += 1
    count +=1

#Add a tie breaker here
#check if 2 values the same and create a tie breaker
result = {}
for val in names_dictionary:
    if names_dictionary[val] in result:
        result[names_dictionary[val]].append(val)
    else:
        result[names_dictionary[val]] = [val]

#Go through the ties and put in order
for key in result:
    ties = list(result[key])
    
    #Checks if each number has more than one person
    if len(ties) > 1:
        nameNum = len(names)
        if len(names) < 100:
                divBy = 100
        else:
            divBy = 1000
        tieBreaker = random.sample(ties, len(ties))
        for tie in tieBreaker:
            indexPlace = tieBreaker.index(tie)
            names_dictionary[tie] += (nameNum-indexPlace)/divBy

#sort the list so they will go from highest number to smallest
sort_winners = sorted(names_dictionary.items(), key=lambda x: x[1], reverse=True)

#Print the list one line at a time
for i in sort_winners:
	print(i[0], i[1])

Related Articles

Website Contact form using AWS

Website Contact form using AWS

For the next iteration of the HTML form was to set it up to send an email to the web owner using AWS. The purpose behind this is, if you have a HTML site and don’t want to purchase a monthly plan or build and maintain server software. Using AWS for this functionality...

read more
HTML with JavaScript contact form

HTML with JavaScript contact form

Link to the form: https://www.lynnamacher.com/pdf/contactForm_V1.html This is created to be basic test for an AWS contact form test. The full form when filled out will send an email through AWS to the site owner. Instead of creating the normal test form I try to...

read more
Sometimes the low-tech approach is the best way

Sometimes the low-tech approach is the best way

Have a family member looking to get me some family videos they had digitized, in one big file, about 80GB (they may not have optimized or know how). The need: The family member’s internet connection isn’t the best and could get disconnected at times, when this happens...

read more

Pin It on Pinterest

Share This