Home > Enterprise >  Generating dictionary does not always work
Generating dictionary does not always work

Time:10-18

I am trying to generate a dictionary automatically with a for loop (i < numero_usuarios), the keys are taken from a list with names, and the values are randomly generated with a random.randint(1, 10), the problem is that it does not always generate the amount I want.

For instance, I want to create 10 users(usuarios), it sometimes creates 7, 8 or 9, but rarely 10.

Code below.

import random

class practica6:

#Create our constructor
    def __init__(self) -> None:
        # Initialize users dictionary
        self.usuarios = {}
        #List of possible names the users can take
        self.nombres = ['Mario', 'Pepe', 'Angel', 'Joaquin', 'Jesus', 'Edson', 'Emilio', 
        'Eli', 'Francisco', 'Sergio', 
        'Erick', 'David', 'Liam', 'Noah', 'Oliver', 'William', 'James', 'Benjamin', 'Lucas', 
        'Henry', 'Alexander', 
        'Mason', 'Michael', 'Ethan', 'Mateo', 'Sebastian', 'Jack', 'Peter', 'Josh', 
        'Patricia', 'Luis', 'Gerardo', 'Carmen']


    def generar_diccionario_usuarios(self, numero_usuarios : int):
        #Generate a dictionary with random names (keys) and random priority (values) keys : 
        #values
        for i in range(numero_usuarios):
            self.usuarios[random.choice(self.nombres)] = random.randint(1, 10)
        #DEBUG : Print our users dictionary
        print(self.usuarios)

#Test app
practica = practica6()
n = 10
print('Usuarios:')
practica.generar_diccionario_usuarios(n)

CodePudding user response:

In a dictionary, a key cannot appear multiple times, and all attempts to insert a key which exists already will result in overwriting the stored value. random.choice, being a draw with replacement, can return the same user multiple times. You need to use random.sample, which simulates a draw without replacement:

for nombre in random.sample(self.nombres, numero_usuarios):
    self.usuarios[nombre] = random.randint(1, 10)

CodePudding user response:

the problem is that sometimes the "random.choice(self.nombres)" generates the same name so it overights, so the solution is :

import random
class practica6:

#Create our constructor
   def __init__(self) -> None:
       # Initialize users dictionary
       self.usuarios = {}
       #List of possible names the users can take
       self.nombres = ['Mario', 'Pepe', 'Angel', 'Joaquin', 'Jesus', 'Edson', 'Emilio', 
       'Eli', 'Francisco', 'Sergio', 
       'Erick', 'David', 'Liam', 'Noah', 'Oliver', 'William', 'James', 'Benjamin', 'Lucas', 
       'Henry', 'Alexander', 
       'Mason', 'Michael', 'Ethan', 'Mateo', 'Sebastian', 'Jack', 'Peter', 'Josh', 
       'Patricia', 'Luis', 'Gerardo', 'Carmen']


   def generar_diccionario_usuarios(self, numero_usuarios : int):
       #Generate a dictionary with random names (keys) and random priority (values) keys : 
       #values
       for i in range(numero_usuarios):
           name = random.choice(self.nombres)
           while name in self.usuarios.keys():
               name = random.choice(self.nombres)
           self.usuarios[name] = random.randint(1, 10)
       #DEBUG : Print our users dictionary
       print(self.usuarios)

#Test app
practica = practica6()
n = 10
print('Usuarios:')
practica.generar_diccionario_usuarios(n)

thank you, hope it wokrs cuz it worked for me!

CodePudding user response:

It's because you get duplicate keys in your dict when choosing one randomly at a time.

You could generate a list of numero_usarios distinct keys with

distinct_names = random.sample(self.nombres, k=numero_usarios)

and a list of random integers with

values = random.choices(range(1, 11), k=numero_usarios)

Then you can build the dict by pairing these lists with

self.usuarios =  dict(zip(distinct_names, values))

CodePudding user response:

I think the problem is that sometimes, when picking a random name- that name could already be in the dict. Why not randomise the names from the start, and as they are added to the dict, remove them from the list?

import random

class Practica6:

    def __init__(self) -> object:
        # Initialize users dictionary
        self.usuarios = {}
        #List of possible names the users can take- shuffled
        self.nombres = random.shuffle(['Mario', 'Pepe', 'Angel', 'Joaquin', 'Jesus', 'Edson', 'Emilio', 
        'Eli', 'Francisco', 'Sergio', 
        'Erick', 'David', 'Liam', 'Noah', 'Oliver', 'William', 'James', 'Benjamin', 'Lucas', 
        'Henry', 'Alexander', 
        'Mason', 'Michael', 'Ethan', 'Mateo', 'Sebastian', 'Jack', 'Peter', 'Josh', 
        'Patricia', 'Luis', 'Gerardo', 'Carmen'])


    def generar_diccionario_usuarios(self, numero_usuarios : int):
        #Generate a dictionary with random names (keys) and random priority (values) keys : 
        #values
        for i in range(numero_usuarios):
            chosen = self.nombres.pop() # random.choice(self.nombres)
            self.usuarios[chosen] = random.randint(1, 10)
        #DEBUG : Print our users dictionary
        print(self.usuarios)



#Test app
practica = Practica6()
n = 5
print('Usuarios:')
practica.generar_diccionario_usuarios(n)

The init always returns an instance of the class. I think this code above may achieve what you are looking for? Alternatively it might be good to make a "factory" function to generate many instances of an object with varying properties, rather than have it as a method. Just a thought.

  • Related