I keep getting indexerrors on a name generator that I wrote

51 Views Asked by At

The code runs just fine for a while before resulting in an index error. This is the error message I keep getting This is the code:

import random
import time

Male_First_Names = ['Albert', 'Arnold', 'Alexander', 'Andrew', 'Bernard', 'Bertrand', 'Charles', 'Christopher', 'Conall', 'Craig', 'Derrick', 'Donald', 'Dwight','Douglas', 'Erwin', 'Edward', 'Elmer', 'Ernest', 'Frederick', 'Gerald', 'Garfield', 'Godfrey', 'George', 'Henry', 'Hubert', 'Howard', 'Herman', 'Jonathan', 'James', 'Jack', 'Kevin', 'Karl', 'Kenneth', 'Keith', 'Lawrence', 'Ludwig', 'Lloyd', 'Mark', 'Nicholas', 'Oscar', 'Oswald', 'Paul', 'Philip', 'Richard', 'Ralph', 'Scott', 'William', 'Wilbur', 'Walter']
Last_Names = ['Clark', 'Smith', 'Thompson', 'Lewis', 'Martin', 'Wright', 'Hughes', 'Stewart', 'Campbell', 'Adams']

x = True
while x == True:
    y = len(Male_First_Names)
    y1 = y-1
    
    z = len(Last_Names)
    z1 = z-1
    r = Male_First_Names[random.randint(0, y1)]
    
    Male_First_Names.remove(r)
    
    print(r+' ' + Male_First_Names[random.randint(0, y1)]+' '+ Last_Names[random.randint(0, z1)])
    
    Male_First_Names.insert(len(Male_First_Names),r)
    time.sleep(0.25)

I wrote a name generator which generators names with a first name, last name, and middle name. It has 2 lists, one with first names, and the other with last names. The code basically picks an element (name) from the first names list at random and uses it as the first name. Then it temporarily removes that name from the list and picks another name from the first names list and uses that name as the middle name. Then it picks an element from the last names list at random and uses it as the last name. Lastly, it inserts the first name that was picked and inserts it back into the first names list and repeats the process. The problem is that while the code runs just fine for a while, an index error eventually occurs. I know that index errors occur when trying to access an element using an index that is outside the valid range of indices for that particular sequence; however, I don't see why that error keeps occurring. What is the problem and how do I fix it?

3

There are 3 best solutions below

0
John3136 On

You modify the list of first names but don't change y1 - the last valid index. so when you do:

print(r+' ' + Male_First_Names[random.randint(0, y1)]+' '+ Last_Names[random.randint(0, z1)])

You always run the rick of the middle name going off the end of the list.

print(r+' ' + Male_First_Names[random.randint(0, y1-1)]+' '+ Last_Names[random.randint(0, z1)])

Would be one way to fix it, but I'd probably use a new variable to make it clearer what is going on - it's already hard to read.

0
Mark Tolonen On

You don't update the length after removing a first name so if randint picks the last item it isn't there.

Instead, use random.sample() to choose two or more names, and random.choice() to pick one name and skip figuring out indices.

import random
import time

male_names = ['Albert', 'Arnold', 'Alexander', 'Andrew', 'Bernard', 'Bertrand', 'Charles', 'Christopher', 'Conall', 'Craig', 'Derrick', 'Donald', 'Dwight','Douglas', 'Erwin', 'Edward', 'Elmer', 'Ernest', 'Frederick', 'Gerald', 'Garfield', 'Godfrey', 'George', 'Henry', 'Hubert', 'Howard', 'Herman', 'Jonathan', 'James', 'Jack', 'Kevin', 'Karl', 'Kenneth', 'Keith', 'Lawrence', 'Ludwig', 'Lloyd', 'Mark', 'Nicholas', 'Oscar', 'Oswald', 'Paul', 'Philip', 'Richard', 'Ralph', 'Scott', 'William', 'Wilbur', 'Walter']
last_names = ['Clark', 'Smith', 'Thompson', 'Lewis', 'Martin', 'Wright', 'Hughes', 'Stewart', 'Campbell', 'Adams']

while True:
    # sample(...,k=2) returns two names *without replacement*
    first, middle = random.sample(male_names, k=2)
    print(f'{first} {middle} {random.choice(last_names)}')
    time.sleep(.25)
2
Ruslan Nakibov On

In the beginning there are 48 first names. Then you do y1 = y-1 so that randint chooses from 0 to 47, which is 48 elements. Then you remove one of first names, so there are 47 of those, yet you use randint(0,47) again. At some point it picks 47 crashing the script.

r = Male_First_Names[random.randint(0, y1)] #pick from 48 numbers
Male_First_Names.remove(r) #length = 47
print(r+' ' + Male_First_Names[random.randint(0, y1)] #pick from 48 again

Revised:

y = len(Male_First_Names)
z = len(Last_Names)
while True:
    ind_firstname = random.randrange(y)
    r = Male_First_Names[ind_firstname]
    middle_names = Male_First_Names.copy()
    middle_names.pop(ind_firstname)

    print(
        " ".join([
            r,
            middle_names[random.randrange(len(middle_names))],
            Last_Names[random.randrange(z)],
        ])
    )
    if condition:
        break
    time.sleep(0.25)
  1. There's no need to call len every time
  2. It's better imo to make a copy, pop element and use copy, than to remove/insert
  3. randrange is easier to implement since it can take 1 number, so just give it length of list
  4. Use while True (better than comparing to True), use break if condition happens to stop loop.