I have a form that expects a unique 5-character ID. I have a function that generates this unique ID. Before entering it in the form, I want to compare it with an existing list of IDs. If the generated ID doesn't exist in the list, pass it in a variable; if it does exist and it isn't unique, generate another ID. What's the best way to go about this?
def generate_id():
random_id= ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5))
return random_id
existing_ids = ['AAAAA', 'BBBBB', 'CCCCC']
for id in existing_ids:
if not generate_id() == id:
unique_id = generate_id()
while True:
a = generate_id()
if a not in set(existing_ids) :
break
Debugging:
for id in existing_ids:
This denotes the execution of the loop for the number of items in the existing_ids, which is definitely not what you want.
if not generate_project_id() == id:
unique_id = generate_project_id()
Apart from the incorrect method name, generate_project_id() should have been generate_id(), this will not do what you think it will, i.e. even if the id is unique it will store a different id in the unique_id since it is calling the method again, unique_id = generate_project_id() and who knows it could be a dupe!
Hence:
If the intention is to keep generating unique id's until one that does not exist in the existing list show up, put it in a loop using set() to exclude any dupes in the existing list:
import string
def generate_id():
random_id = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5))
return random_id
existing_ids = ['AAAAA', 'BBBBB', 'CCCCC']
while True:
genId = generate_id()
if genId not in set(existing_ids):
unique_id = genId
break
import random
import string
def generate_id():
random_id = ''
random_id = ''.join(random.choice
(string.ascii_uppercase + string.digits) for _ in range(5))
return random_id
existing_ids = ['AAAAA', 'BBBBB', 'CCCCC']
unique_id = generate_id()
while unique_id in existing_ids:
unique_id = generate_id()
if unique_id not in existing_ids:
break;
print(unique_id)
I think you could try bitmap? Because 5 chars could construct a number which < 2**32, so you can generate a random number [0-26**6] and use it to mod 26 to get the only 5 chars,
you can use bitmap to check if it exists.
Related
I have this below set of code where I perform some manipulation based after pulling some data from a source Dataframe called df.
Customer_data = []
for i in range(0, len(df)):
try:
Customer = (re.search(r'(Customer"=>).*?(,)', df[i]).group(0).split('=>')[1].replace('"','').replace(',',''))
except:
Customer = ''
Customer_data.append(Customer)
Customer = pd.DataFrame(Customer_data.append, columns = ['Customer'])
I am trying to have the above code repeated for set of variables wherein I would replace the variable Customer with another variable. How could I generalise the above code such that it could be reused for other variables as well in a loop.
Example variables : Product, ModelName
You can put it inside the function, where you pass the name string of your variable (as seen in DataFrame).
Just change search part to include correct name r'({}"=>).*?(,)'.format(name).
def my_func(df, name):
Customer_data = []
for i in range(0, len(df)):
try:
Customer = (re.search(r'({}"=>).*?(,)'.format(name), df[i]).group(0).split('=>')[1].replace('"','').replace(',',''))
except:
Customer = ''
Customer_data.append(Customer)
Customer = pd.DataFrame(Customer_data.append, columns = ['Customer'])
return Customer
# run function
Product = my_func(df, 'Product')
ModelName= my_func(df, 'ModelName')
You can define the regex as a string, adding there the column name from a variable. Finally passing that regex expression to re.search:
col_name = "Customer"
my_regex = r"('+re.escape(col_name)+'=>).*?(,)"
Customer_data = []
for i in range(0, len(df)):
try:
Customer = (re.search(my_regex, df[i]).group(0).split('=>')[1].replace('"','').replace(',',''))
except:
Customer = ''
Customer_data.append(Customer)
Customer = pd.DataFrame(Customer_data.append, columns = ['Customer'])
I am trying to loop through my One2Many records to avoid duplication.
class sales_target(models.Model):
_name = 'sales.target'
_description = 'Sales Target'
name = fields.Char(string='Name',required=True)
from_date = fields.Date(string='From Date',required=True)
to_date = fields.Date(string='To Date',required=True)
sales_team = fields.Many2one('crm.team',required=True)
sales_record_ids = fields.One2many('sales.target.record','sales_target_rec_id',string='Sales Record')
#api.one
def check_duplication(self,result):
count = 0
if self.sales_record_ids:
for record in self.sales_record_ids:
if result.id == record.sales_person_p_id:
count = 1
if count == 0:
self.write({'sales_record_ids':[(0,0,{'sales_person':result.name})]})
#api.one
def get_sales_person(self):
for res in self.sales_team.member_ids:
self.check_duplication(res)
The other class is as:
class sales_target_record(models.Model):
_name = 'sales.target.record'
sales_target_rec_id = fields.Many2one("sales.target")
sales_person = fields.Char(string='Sales Person',readonly=True,required=True)
sales_person_p_id = fields.Char(compute='get_value',store=True)
#api.onchange('sales_person')
#api.depends('sales_person')
def get_value(self):
res = self.env['res.partner'].search([('name','=',self.sales_person)])
self.sales_person_p_id = res[0].id
Now when I am hitting the button i still have duplicate records. However I tried to compare with name and things work good but I cannot compare with names since its not correct because names can be same but id cannot. That function was as:
#api.one
def check_duplication(self,result):
count = 0
if self.sales_record_ids:
for record in self.sales_record_ids:
if result.name == record.sales_person:
count = 1
if count == 0:
self.write({'sales_record_ids':[(0,0,{'sales_person':result.name})]})
Hope for guidance on this.
Can you try like this
#api.multi
def check_duplication(self,result):
if self.sales_record_ids:
for record in self.sales_record_ids:
if not result.name == record.sales_person:
self.write({'sales_record_ids':[(0,0,{'sales_person':result.name})]})
Concluding from the fact that for name it works properly, something might be wrong with your if condition.
sales_person_p_id is of type char, however you seem to compare it with an integer: result.id.
Have you made sure that both objects in your if condition are of the same type?
Try to make sales_person_p_id an integer field (e.g. via sales_person_p_id = fields.Integer(compute='get_value',store=True) or do some kind of type casting before comparing the objects.
I created a program that reads a couchDB to list followers and friends ids of a single twitter user. Friends are identified under the group “friend_edges” and followers under “follower_edges”.
I use the intersection operation between sets -set1.intersection(set.2)- in order to obtain the list of those who are both friends and followers.
When I use print to see the outputs, the results are correct. But when I change to return to process the results, it only processes friends, not followers.
Can somebody give me a clue of what I'm doing wrong and how to improve the code?.... thanks in advance.
from twitter_login import oauth_login
from twitter_DB import load_from_DB
from sets import Set
def friends_and_followers(doc):
if 'friend_edges' in doc.keys():
flist = []
for x in doc['friend_edges']:
flist.append(x)
#print "Number of friends: ", len(flist) <-- shows the right number of items
return flist
else:
return []
if 'follower_edges' in doc.keys():
followlist = []
for x in doc['follower_edges']:
followlist.append(x)
#print "Number of followers: ", len(followlist) <-- shows the right number of items
return followlist
else:
return []
flist = Set(flist)
followlist = Set(followlist)
return flist.intersection(followlist)
if __name__ == '__main__':
twitter_api = oauth_login()
DBname = 'users-aguy-+-only'
ff_results = load_from_DB(DBname)
print 'number loaded', len(ff_results)
for doc in ff_results:
together = friends_and_followers(doc)
print "Friends and followers of a guy: ", together
A return statement stops execution of that method and returns to the calling method, so by adding a return statement you are saying, "Stop here and go back to where you came from"
You need to store both the values you want returned in variables and return them at the same time at the end of your method:
return value1, value2
You will call this with something like this:
val1, val2 = get_value1_and_value2(input)
It might make more sense to just break that up into two separate methods that each return the correct value though.
My First Attempt :
def generate_id():
""" Create unique id of alphanumeric characters """
i = 0
id = ''
while i!=10:
id = id + random.choice(string.ascii_letters + string.digits)
i+=1
if check_unique(id):
return id
id = generate_id()
return id
def check_unique(id):
"""Check if id is unique"""
try:
instances = SomeModel.objects.get(id=id)
except ObjectDoesNotExist:
return True
return False
Second Way :
def generate_id():
""" Create unique id of alphanumeric characters """
i = 0
id = ''
while i!=10:
id = id + random.choice(string.ascii_letters + string.digits)
i+=1
if check_unique(id):
return id
generate_id()
def check_unique(id):
"""Check if id is unique"""
try:
instances = SomeModel.objects.get(id=id)
except ObjectDoesNotExist:
return True
return False
If I do it the second way , won't my logic of generating unique id's be wrong ? Because I might loose the id from the last call .
I am new to python and I don't know but I think my recursion concept looks messed up
Follow your code:
if check_unique(id): # If this is `false`, you keep going
return id
generate_id() # Now what? You call the function. Nothing gets returned.
If you want to create a unique ID, don't use recursion. Just use a while loop and generate new IDs as long as they're not unique:
characters = string.ascii_letters + string.digits
def generate_id(length=10):
return ''.join(random.choice(characters) for i in range(length))
def generate_unique_id(length=10):
id = generate_id(length)
while not check_unique(id):
id = generate_id(length)
return id
In the second way you should return a the end of the generate_id function:
return generate_id()
I would also suggest to make an iteration instead of a recursive call... it's seems cleaner in this situation.
Tried the following, where "objectname" contains a string name, to be assigned on creation of an object.
for record in result:
objectname = 'Customer' + str(record[0])
print objectname
customername = str(record[1])
objectname = Customer(customername)
Where Customer is a class.
In my test, this loop runs twice printing "objectname" as Customer1 and Customer2, yet creates 2 objects, but the objects are called "objectname" (it overwrites each loop), opposed to the 2 unique objects Customer1 or Customer2.
Its simply not assigning strings(customer1,2) inside the variable, but purely the variables name.
I've tried assigning strings to the object name, but that gives a syntax error
Surely this must be done all the time, thanks for your help in advance.
Instead of using a new variable for each customer you could store your object in a Python dictionary:
d = dict()
for record in result:
objectname = 'Customer' + str(record[0])
customername = str(record[1])
d[objectname] = Customer(customername)
print d
An example of objects stored in dictionaries
I just could'nt help my self writting some code (more than I set out to do). It's like addictive. Anyway, I would'nt use objects for this kind of work. I probably would use a sqlite database (could be saved in memory if you want). But this piece of code show you (hopefully) how you can use dictionaries to save objects with customer data in:
# Initiate customer dictionary
customers = dict()
class Customer:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
self.address = None
self.zip = None
self.state = None
self.city = None
self.phone = None
def add_address(self, address, zp, state, city):
self.address = address
self.zip = zp
self.state = state
self.city = city
def add_phone(self, number):
self.phone = number
# Observe that these functions are not belonging to the class.
def _print_layout(object):
print object.fname, object.lname
print '==========================='
print 'ADDRESS:'
print object.address
print object.zip
print object.state
print object.city
print '\nPHONE:'
print object.phone
print '\n'
def print_customer(customer_name):
_print_layout(customers[customer_name])
def print_customers():
for customer_name in customers.iterkeys():
_print_layout(customers[customer_name])
if __name__ == '__main__':
# Add some customers to dictionary:
customers['Steve'] = Customer('Steve', 'Jobs')
customers['Niclas'] = Customer('Niclas', 'Nilsson')
# Add some more data
customers['Niclas'].add_address('Some road', '12312', 'WeDon\'tHaveStates', 'Hultsfred')
customers['Steve'].add_phone('123-543 234')
# Search one customer and print him
print 'Here are one customer searched:'
print 'ooooooooooooooooooooooooooooooo'
print_customer('Niclas')
# Print all the customers nicely
print '\n\nHere are all customers'
print 'oooooooooooooooooooooo'
print_customers()
It is generally not that useful to have dynamically generated variable names. I would definitely suggest something like Niclas' answer instead, but if you know this is what you want here is how you can do it:
for record in result:
objectname = 'Customer' + str(record[0])
print objectname
customername = str(record[1])
exec '%s = Customer(%r)' % (customername, customername)
This will result in the variables Customer1 and Customer2 being added to the innermost scope, exactly like if you had executed the following lines:
Customer1 = Customer('Customer1')
Customer2 = Customer('Customer2')
When doing it this way you need to make sure that customername is a valid Python identifier.
What you need is a dictionary:
customers = {}
for record in result:
objectname = 'Customer' + str(record[0])
customers[customername] = Customer(str(record[1])) #assignment to dictionary