Dynamically generating dictionary entries with unique names - python

I'm trying to dynamically generate cells. Each cell has a name, defined as a key of a dictionary. The value is an instance of a class, containing three parameters (strength, intelligence, energy).
import random
class Cell:
def __init__(self, energy, strength, intelligence):
self.energy = energy
self.strength = strength
self.intelligence = intelligence
cells = {}
k = 1
while k < 100:
key = "a" + str(k)
print("Generating cell: " + key)
cells[key] = Cell(random.randint(1, 100),random.randint(1, 100),random.randint(1, 100))
k += 1 #Generate cells
My problem is with names. This code was good enough for the first generation of cells, but when I need to make more, the new cells can override old ones due a name conflict.
Is there a way to generate random, but unique cell names to avoid such conflict? I tried to create new names starting with 'a' and the lowest number which doesn't already exist. However, cells die throughout my program. My approach would simply fill in the gaps, which would make it hard to determine which generation the cell is from.

You could use python's uuid library.
Simple example (out of context):
import uuid as uuidlib
uuid = str(uuidlib.uuid4())
In your case:
import uuid
import random
class Cell:
def __init__(self, energy, strength, intelligence):
self.energy = energy
self.strength = strength
self.intelligence = intelligence
cells = {}
k = 1
while k < 100:
key = str(uuid.uuid4())
print("Generating cell: " + key)
cells[key] = Cell(random.randint(1, 100),random.randint(1, 100),random.randint(1, 100))
k += 1 #Generate cells

You can try this function to generate random names
import random
def random_string(min_size, max_size):
import string
return ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=random.randint(min_size, max_size)))
random_string(7, 15)
This gives output like
'AvkyCzlN9ggPr' and if you run again it may give 'FBPXy5a4Ib'
Also you can add a version/generation field to your cell class in addition to energy, strength, intelligence. You can add a counter to get the current version and increment the version every time the cell is updated.
Based on what your requirements are you can then use it to remove old cells, or keep them as a version history.
To remove old cells, just override a dictionary value with random_string()
For eg:-
some_dict = {}
randomstr = random_string(7, 15)
some_dict[random_str] = some_cell(randomstr)
to override
some_updated_cell = some_cell.update() # decide to increment your version? upto you.
# If you keep the randomstr same it will override the dict key, else it will not override and you can make (randomstr +"-"+ str(version)) as the key of dict.
some_dict[some_updated_cell.get_randomstr] = some_updated_cell
to not overwrite and keep track of generation
version = 1 # build a method or autoincrement version.
key = randomstr + "-" + str(version)
then you can do key.split("-") to get the key and the version from 'AvkyCzlN9ggPr-1'.
Another alternative approach would be to use the dictionary values as a list of objects. So instead of replacing the dictionary value, you can append it to the list.
some_dict[randomstr] = []
some_dict[randomstr] = [*some_dict[randomstr], newObject]
And to access the latest generation just do
some_dict[random_str][-1] # to access the last element of list
If this does not solve your problem leave a comment and I'll update accordingly :)

Related

Python dictionary keys seem to vanish before I delete them

I'm a newbie programmer working on an idea for a small game. I wanted my play space to be a grid for various reasons. Without a lot of good reason, I decided to create a class of GridSquare objects, each object having properties like size, an index to describe what (x,y) coordinates they represented, and some flags to determine if the grid squares were on land or empty space, for example. My grid is a dictionary of these objects, where each GridSquare is a key. The values in the dictionary are going to be various objects in the place space, so that I can easily look up which objects are on each grid square.
Just describing this I feel like a complete lunatic. Please bear in mind that I've only been at this a week.
My problem appears when I try to change the GridSquare objects. For example, I want to use a list to generate the land on each level. So I iterate over the list, and for each value I look through my grid squares using a for loop until I find one with the right index, and flip the GridSquare.land property. But I found that this caused a runtime error, since I was changing keys in a dictionary I was looping through. OK.
Now what I'm trying to do is to create a list of the keys I want to change. For each item in my level-generating list, I go through all the GridSquares in my grid dictionary until I find the one with the index I'm looking for, then I append that GridSquare to a list of old GridSquares that need updating. I then make another copy of the GridSquare, with some properties changed, in a list of altered GridSquares. Finally, I delete any keys from my grid dictionary which match my list of "old" GridSquares, and then add all of the altered ones into my grid dictionary.
The problem is that when I delete keys from my grid dictionary which match my list of "old" keys, I run into keyerrors. I can't understand what is happening to my keys before I can delete them. Using try/except, I can see that it's only a small number of the keys, which seems to vary kind of arbitrarily when I change parts of my code.
I would appreciate any insight into this behaviour.
Here is code for anyone still reading:
aspect_ratio = (4, 3)
screen_size = (1280, 720)
#defining a class of objects called GridSquares
class GridSquare:
def __init__(self, x, y):
self.index = (x, y)
self.land = 0
#creates a dictionary of grid squares which I hope will function as a grid......
grid = {}
for x_index in range(1, (aspect_ratio[0] + 1)):
for y_index in range (1, (aspect_ratio[1] + 1)):
new_square = GridSquare(x_index, y_index)
grid[new_square] = None
#these are lists to hold changes I need to make to the dictionary of grid squares
grid_changes = []
old_gridsquares = []
#this unweildly list is meant to be used to generate a level. Numbers represent land, spaces are empty space.
for number_no, number in enumerate(["1", "1", "1", "1",
" ", " ", " ", " ",
"1", "1", "1", "1"]):
#makes grid squares land if they are designated as such in the list
for gridsquare in grid.keys():
#this if statement is meant to convert each letter's position in the list into an index like the grid squares have.
if gridsquare.index == ((number_no + 1) % (aspect_ratio[0]), ((number_no + 1) // (aspect_ratio[0] + 1)) + 1):
#create a list of squares that need to be updated, and a list of squares to be deleted
old_gridsquares.append(gridsquare)
flagged_gridsquare = GridSquare((number_no + 1) % (aspect_ratio[0]), ((number_no + 1) // (aspect_ratio[0] + 1)) + 1)
flagged_gridsquare.land = 1
#this part is meant to set the flag for the gridsquare that indicates if it is on the far side or the near side,
#if it is land
if number == "1":
flagged_gridsquare.near = 1
grid_changes.append(flagged_gridsquare)
#deletes from grid any items with a key that matches the old squares, and adds updated versions.
for old_gridsquare in old_gridsquares:
try:
del grid[old_gridsquare]
except:
print(old_gridsquare.index)
print(old_gridsquare.land)
for grid_change in grid_changes:
grid[grid_change] = None

Searching a set of dictionary values for a specific key, then building a separate dictionary with the found keys values results

It's been awhile since I last asked a question in here. Well, I am stumped on this issue I am trying to resolve. I am trying to create a permissions table for Power BI. I want create two separate dictionaries for direct reports and indirect reports for a manager or people leader. I decided as a beginner with data wrangling to leverage Python and Pandas for this. Here is the sample HR data I created:
I have managed to create an output of the following:
What I am trying to create is an output like this:
I believe it's something really simple that I am not taking into account. Any help would be greatly appreciated. Here is a copy of my current code:
import pandas as pd
import time
import json
def time_format(seconds: int):
'''
:param seconds:
:return:
'''
if seconds is not None:
seconds = int(seconds)
d = seconds // (3600 * 24)
h = seconds // 3600 % 24
m = seconds % 3600 // 60
s = seconds % 3600 % 60
if d > 0:
return '{:02d}D {:02d}H {:02d}m {:02d}s'.format(d, h, m, s)
elif h > 0:
return '{:02d}H {:02d}m {:02d}s'.format(h, m, s)
elif m > 0:
return '{:02d}m {:02d}s'.format(m, s)
elif s > 0:
return '{:02d}s'.format(s)
return '-'
# Create Dataframe
data = pd.read_csv('Sample HR Data.csv')
df = pd.DataFrame(data)
business_data = list(df.itertuples(index=False, name=None))
start_time = time.perf_counter()
# Build array of direct reports
direct_reports = dict()
for emp_data in business_data:
if(emp_data[1]==emp_data[5]):
continue
if emp_data[1] not in direct_reports:
direct_reports[emp_data[1]] = []
# managers
if emp_data[5] not in direct_reports:
direct_reports[emp_data[5]] = [emp_data[1]]
else:
direct_reports[emp_data[5]].append(emp_data[1])
# Method to create indirect report dictionary
indirect_report = dict()
for emp_data in business_data:
# Getting the IDs of all managers
if emp_data[2] == "Y":
manager = emp_data[1]
print(manager)
# Getting the values of all the people leaders
if emp_data[3] == "Y":
ppl_leader_directs = direct_reports.get(emp_data[1])
print(ppl_leader_directs)
# Here is where I start to bang my head against the wall.
# Now I feel woozy..
# This does not give me any results, I have tried a few different ways to solve this
if manager in ppl_leader_directs:
print("I found: ",emp_data[0])
# Count the number of employees
employee_count = dict()
for manager in direct_reports:
employee_count[manager] = len(direct_reports[manager])
for employee in direct_reports[manager]:
employee_count[manager] += len(direct_reports[employee])
# Build the final table for RLS use
for emp_data in business_data:
for key, value in direct_reports.items():
if emp_data[1] == key:
direct_report = value
for key, value in employee_count.items():
if emp_data[1] == key:
direct_count = value
print(emp_data[0],emp_data[1],emp_data[2],emp_data[3],emp_data[4],direct_count,direct_report)
end_time = time.perf_counter()
run_time = end_time - start_time
print("Processing total time: ", time_format(run_time))
Here are the sites I used to create the current state of my code. I emboldened the two sites I initially used.
References:
How to search if dictionary value contains certain string with Python
Python update a key in dict if it doesn't exist
https://thispointer.com/python-4-ways-to-print-items-of-a-dictionary-line-by-line
https://www.techiedelight.com/find-employees-who-reports-to-manager
https://www.geeksforgeeks.org/find-number-of-employees-under-every-manager
https://avleonov.com/2019/08/12/how-to-get-the-organization-units-ou-and-hosts-from-microsoft-active-directory-using-python-ldap3
Searching a dictionary for a key, adding the value of that key's value to another key value pair
making a dictionary from another dictionary by searching keys
https://www.w3schools.com/python/ref_dictionary_setdefault.asp
dictionary append another dictionary to specific key

How can I keep track of what combinations have been tried in a brute force approach?

I'm using Python 3 to create a brute-force Vigenere decipher-er. Vigenere codes are basically adding strings of letters together.
The way I want my code to work is the user puts in however any keys they want (this bit's done), the letters are turned into their numbers (also done) then it adds every pair of keys together (working on this, also what I need help with) and prints out the two keys and what they added to.
To do this, I need to be able to keep track of which pairs of keys have been added together. How can I do this?
BTW, my current code is this. I'm doing this both fro the decoding and the programming practice, so I really just want the way to keep track of added key pairs, not the whole program.
#defines start variables
import math
alph = "abcdefghijklmnopqrstuvwxyz"
keyqty = int(input("how many keys?"))
listofkeys = []
listofindex = []
timer = 0
#gets keys
while True:
if timer >= keyqty:
break
else:
pass
listofkeys.append(input("key: ").lower())
timer += 1
tempkey = ""
#blank before key
for item in listofkeys:
listofindex.append("")
for letter in item:
listofindex.append(alph.find(letter)
timer = 0
newkey = False
key1index = []
key2index = []
endex = []
printletter = ""
doneadds = []
Obviously, it still needs some other work, but some help would be appreciated.
You can either use a set for fast lookup (amortized constant time).
tried = set()
for ...
if word not in tried:
try()
tried.add(word)
or use itertools.product() to generate your trials without the need of keeping track of the already tried ones.
for password in itertools.product(alph, repeat=keyqty):
try(password)

Comparing two tables with SQLAlchemy

I am having a great deal of trouble with this problem. I am trying to compare two different tables from two different databases to see what tuples have been added, what tuples have been deleted, and what tuples have been updated. I do that with the following code:
from sqlalchemy import *
# query the databases to get all tuples from the relations
# save each relation to a list in order to be able to iterate over their tuples multiple times
# iterate through the lists, hash each tuple with k, v being primary key, tuple
# iterate through the "after" relation. for each tuple in the new relation, hash its key in the "before" relation.
# If it's found and the tuple is different, consider that an update, else, do nothing.
# If it is not found, consider that an insert
# iterate through the "before" relation. for each tuple in the "before" relation, hash by the primary key
# if the tuple is found in the "after" relation, do nothing
# if not, consider that a delete.
dev_engine = create_engine('mysql://...')
prod_engine = create_engine('mysql://...')
def transactions(exchange):
dev_connect = dev_engine.connect()
prod_connect = prod_engine.connect()
get_dev_instrument = "select * from " + exchange + "_instrument;"
instruments = dev_engine.execute(get_dev_instrument)
instruments_list = [r for r in instruments]
print 'made instruments_list'
get_prod_instrument = "select * from " + exchange + "_instrument;"
instruments_after = prod_engine.execute(get_prod_instrument)
instruments_after_list = [r2 for r2 in instruments_after]
print 'made instruments after_list'
before_map = {}
after_map = {}
for row in instruments:
before_map[row['instrument_id']] = row
for y in instruments_after:
after_map[y['instrument_id']] = y
print 'formed maps'
update_count = insert_count = delete_count = 0
change_list = []
for prod_row in instruments_after_list:
result = list(prod_row)
try:
row = before_map[prod_row['instrument_id']]
if not row == prod_row:
update_count += 1
for i in range(len(row)):
if not row[i] == prod_row[i]:
result[i] = str(row[i]) + '--->' + str(prod_row[i])
result.append("updated")
change_list.append(result)
except KeyError:
insert_count += 1
result.append("inserted")
change_list.append(result)
for before_row in instruments_list:
result = before_row
try:
after_row = after_map[before_row['instrument_id']]
except KeyError:
delete_count += 1
result.append("deleted")
change_list.append(result)
for el in change_list:
print el
print "Insert: " + str(insert_count)
print "Update: " + str(update_count)
print "Delete: " + str(delete_count)
dev_connect.close()
prod_connect.close()
def main():
transactions("...")
main()
instruments is the "before" table and instruments_after is the "after" table, so I want to see the changes that occurred to change instruments to instruments_after.
The above code works well, but fails when instruments or instruments_after is very large. I have a table that is over 4 million lines long and simply trying to load that into memory causes Python to exit. I have tried overcoming this issue by using LIMIT, OFFSET in my queries to append to the instruments_lists in pieces, but Python still exits because two lists of that size simply take up too much space. My last option is to choose a batch from one relation, and iterate through batches of the second relation and make comparisons, but that is extremely error prone. Is there another way to circumvent this problem? I have considered allocating more memory to my VM but I feel that the space complexity of my code is the issue and that is what should be fixed first.

Python / linked list / dynamic / overloading

I haven't programmed in a year so I am a little rusty. I really want to incorporate a link list but I am having trouble remembering how the code works, and having to implement it in Python isn't helping.
I only have the Node Class set up so far. Apparently, I cant use overloaded constructors which is annoying...
Basically i want to write a program that prompts a user to enter X number of bucket. Each bucket will have an X amount of different color balls. The user will specify how many balls for each color.
I welcome any help!
class Node:
def __init__(self, bucketNumber ,colorONE, colorTWO,
colorTHREE, colorFOUR, colorFIVE ):
self.bucket = bucketNumber # index
self.color1 = colorONE # quantity
self.color2 = colorTWO # quantity
self.color3 = colorTHREE # quantity
self.color4 = colorFOUR # quantity
self.color5 = colorFIVE # quantity
def printN(bucketNum):
for i in range(0,bucketNum):
print(nodes[i].bucket, nodes[i].color1, nodes[i].color2, nodes[i].color3, nodes[i].color4, nodes[i].color5)
colors = []
nodes = []
count = []
bucketNum = int(raw_input("The are 2-5 buckets with 2-5 ball colors. Enter number of Buckets:"))
colorNum = int(raw_input("Enter number of Colors:"))
for i in range(0,colorNum):
colors.append(raw_input("Enter color: " + str(i+1) ))
for i in range(0,bucketNum):
for j in range(0,colorNum):
count.append((raw_input("How many "+ colors[j] +" balls in bucket " + str(i+1))))
nodes.append( Node(i+1, count[0], count[1], count[2], count[3], count[4]) )
del count[ 0:len(count) ]
for i in range(0,colorNum):
print colors[i],
print " "
printN(bucketNum)
You don't seem to have a question, but note that there is probably no need to use a linked list, unless your list will have many insertions AND be large (because of python list memory allocation; and I wouldn't assume that this was a problem until it showed up in profiling), or if you will have many insertions and deletes at the ends of the list.
In that case, python provides collections.deque which is a linked sequence.

Categories

Resources