Python dictionary dynamic update - python

so I have this dictionary x created from this function
olist = ['a/b/c','a/b/c/d','b/c/d','x/y/z','a/b','d/e/f','i/j/k']
def bulkFeed(objlist):
x = {}
for obj in objlist:
#pdb.set_trace()
dn_len = len(obj)
if dn_len not in x:
x[dn_len] = {}
if obj not in x[dn_len]:
x[dn_len][obj] = {}
x[dn_len][obj].update({"commit":1,"ObjectRef":obj})
return x
obj_dict = bulkFeed(olist)
>>> obj_dict
{3: {'a/b': {'commit': 1, 'ObjectRef': 'a/b'}}, 5: {'a/b/c': {'commit': 1, 'ObjectRef': 'a/b/c'}, 'd/e/f': {'commit': 1, 'ObjectRef': 'd/e/f'}, 'b/c/d': {'commit': 1, 'ObjectRef': 'b/c/d'}, 'x/y/z': {'commit': 1, 'ObjectRef': 'x/y/z'}, 'i/j/k': {'commit': 1, 'ObjectRef': 'i/j/k'}}, 7: {'a/b/c/d': {'commit': 1, 'ObjectRef': 'a/b/c/d'}}}
what I want to do is something like this in obj_dict
if 'a/b/c'.startswith('a/b'):
update commit to 0 in 'a/b/c' level
if 'a/b/c/d'.startswith('a/b/c'):
update commit to 0 in 'a/b/c/d' level
keep doing for every item in dictionary until reaching end of dict
Thanks any answer/headsup will be very helpful.
'a/b/c' stems from inner dictionary level for instance 'a/b/c/d' stems

Related

Retrieve specific fields of a namedtuple instance from a nested list in Python

I am starting a project for school, a basic text-adventure game, where the player navigates through several rooms, each with a set of items, and adds an item to their inventory by spending a turn.
Since each item is unique to a room and each item is also unique in its stat benefits, I have done the following to implement these:
Item = namedtuple('Item', ['name', 'atk', 'defense', 'agi', 'hp'])
#Sport Store Items
bat = Item('Baseball Bat', 3, 1, 0, 0)
shoes = Item('Running Shoes', 0, 1, 3, 0)
dryeggs = Item('Freeze Dried Eggs', 0, 0, 1, 2)
#Clothes Store Items
belt = Item('Studded Belt', 1, 1, 0, 0)
candy = Item('Japanese Candy', 0, 0, 1, 1)
jacket = Item('Leather Jacket', 0, 3, 0, 1)
#Toy Store Items:
cars = Item('Toy Car Pack', 1, 1, 0, 0)
crayons = Item('Crayons', 0, 0, 1, 0)
toygun = Item('Toy Gun', 2, 1, 0, 0)
#Candle Store Items:
jar = Item('Candle Jar', 2, 0, 0, 0)
matches = Item('Matches', 1, 0, 1, 0)
wax = Item('Wax', 0, 2, 1, 0)
#Music Store Items:
disc = Item('Vinyl Disc', 2, 0, 1, 0)
guitar = Item('Electric Guitar', 3, 0, 0, 0)
symbol = Item('Symbol', 1, 2, 0, 0)
all_items = [
[bat, shoes, dryeggs, '1'],
[belt, candy, jacket, '2'],
[cars, crayons, toygun, '3'],
[jar, matches, wax, '4'],
[disc, guitar, symbol, '5']
]
My issue is here, in my get_items function:
def get_items(id):
for i in all_items:
if i[3] == id:
items = i
items = list(items[0:4])
return items
else:
continue
I'm trying to get the list of items based on the matching ID parameter. There is a function in another file that takes the player's current position and sends it to other functions as the map_id. I've successfully made it so the name of the store changes based on this position, but I cannot figure out how to handle these sub-lists to return a specific sub-list based on the id.
For example, in the sport_store code, I'm trying to return the results like so:
def sport_store():
room_id = '1'
item_select = items.get_items(room_id)
#FIXME: import items.py later with this function in it.
if item_select != []:
if entering == True:
print('You enter the Sporting Goods Store.')
print('There aren\'t many supplies left. What will you pick?')
else:
print('There aren\'t many supplies left. What will you pick?')
print(item_select)
However, no matter what things I change in get_items' loop to get it to work, I always return the original empty list of item_selection. I am trying to select the matching sub-list from the all_items global with the get_items function and then use that sub-list to make a new list that gets sent to item_selection showing the items for that store, and then format the namedtuples in it to show just the names value. Is this possible or do I need to convert the data to a dictionary?
you can use a dictionary for all items:
all_items = {
'1':[bat, shoes, dryeggs],
'2':[belt, candy, jacket],
'3':[cars, crayons, toygun],
'4':[jar, matches, wax],
'5':[disc, guitar, symbol]
}
then, instead of calling items.getItems(room_id), you could just do all_items[room_id]. Hope this helps!

Cannot get ordered result

I'm working with Python 3.5.2 and I'm trying to get a dictionary ordered by key by using OrderedDict.
Here is what I'm trying:
import re
from collections import OrderedDict
BRACKETS_PATTERN = re.compile(r"(?P<info>.*)?\((?P<bracket_info>.*?)\)")
def transform_vertical(vertical, trans=True):
# elearning & Massive Online Open Courses (MOOCs) => ELEARNING_AND_MASSIVE_ONLINE_OPEN_COURSES
# Repair & Maintenance (SMB) => SMB_REPAIR_AND_MAINTENANCE
# Digital Advertising & Marketing/Untagged Agencies => DIGITAL_ADVERTISING_AND_MARKETING_OR_UNTAGGED_AGENCIES
if not trans:
return vertical
else:
v = vertical.replace(" & ", "_AND_").replace(", ", "_AND_").replace("/", "_OR_")
brackets_search_result = BRACKETS_PATTERN.search(v)
result = v
if brackets_search_result:
bracket_info = brackets_search_result.group("bracket_info")
info = brackets_search_result.group("info")
if bracket_info.upper() in ("SMB", "CBV"): # todo more prefix
result = bracket_info.upper() + "_" + info
else:
result = info
result = result.replace(" ", "_").upper().strip("_")
return result
VERTICAL_MAP = OrderedDict({
"GAMING": OrderedDict({
"MOBILE_GAMING": 1,
"AR_OR_VR_GAMING": 1,
"CONSOLE_AND_CROSS_PLATFORM_GAMING": 1,
"ESPORTS": 1,
"PC_GAMING": 1,
"REAL_MONEY_GAMING": 1,
}),
"TRAVEL": OrderedDict({
"AUTO_RENTAL": 1,
"RAILROADS": 1,
"HOTEL_AND_ACCOMODATION": 1,
"RIDE_SHARING_OR_TAXI_SERVICES": 1,
"TOURISM_AND_TRAVEL_SERVICES": 1,
"TOURISM_BOARD": 1,
"AIR": 1,
"TRAVEL_AGENCIES_AND_GUIDES_AND_OTAS": 1,
"CRUISES_AND_MARINE": 1,
})
})
s = list(VERTICAL_MAP[transform_vertical("Gaming")].keys())
print(s)
And I get non-ordered result like:
['REAL_MONEY_GAMING', 'AR_OR_VR_GAMING', 'MOBILE_GAMING', 'CONSOLE_AND_CROSS_PLATFORM_GAMING', 'ESPORTS', 'PC_GAMING']
Expected result:
[ 'MOBILE_GAMING', 'AR_OR_VR_GAMING','CONSOLE_AND_CROSS_PLATFORM_GAMING', 'ESPORTS', 'PC_GAMING', 'REAL_MONEY_GAMING']
What's wrong with my code and how to get an ordered result?
Dictionaries are not insertion ordered in Python 3.5.
You are instantiating the ordered dicts with arbitrarily ordered regular dicts. Construct each of the ordered dicts from a list of (key, value) tuples.

How to obtain a value from inside a loop

I will be implementing multiprocessing so that the loops are occurring at the same time, but how can I make it so at the end of each iteration, I can obtain the value of westernEurope.cases and easternEurope.cases so that I can add them together
westernEurope = Region("Western Europe", 1000, 0, 0, 8, 4, 4, 0)
while westernEurope.deaths < westernEurope.population:
westernEurope.infection()
if westernEurope.cases > westernEurope.population:
westernEurope.cases = westernEurope.population
print("Infections:", westernEurope.cases)
westernEurope.death()
if westernEurope.deaths > westernEurope.population:
westernEurope.deaths = westernEurope.population
print("Deaths:", westernEurope.deaths)
#where i want to return the value of westernEurope.cases
time.sleep(0.1)
easternEurope = Region("Eastern Europe", 1000, 0, 0, 8, 4, 4, 0)
while easternEurope.deaths < easternEurope.population:
easternEurope.infection()
if easternEurope.cases > easternEurope.population:
easternEurope.cases = easternEurope.population
print("Infections:", easternEurope.cases)
easternEurope.death()
if easternEurope.deaths > easternEurope.population:
easternEurope.deaths = easternEurope.population
print("Deaths:", easternEurope.deaths)
# where i want to return the value of easternEurope.cases
time.sleep(0.1)
print(easternEurope.cases + westernEurope.cases)
IMHO there is no need for multiprocessing. With a generator, your problem can be solved in an even more elgant way.
# where i want to return the value of easternEurope.cases
yield region.cases
Full code:
def desease(region: Region):
while region.deaths < region.population:
region.infection()
if region.cases > region.population:
region.cases = region.population
print("Infections:", region.cases)
region.death()
if region.deaths > region.population:
region.deaths = region.population
print("Deaths:", region.deaths)
# where i want to return the value of easternEurope.cases
yield region.cases
time.sleep(0.1)
easternEurope = Region("Eastern Europe", 1000, 0, 0, 8, 4, 4, 0)
westernEurope = Region("Western Europe", 2000, 0, 0, 8, 4, 4, 0)
eastDesease = desease(easternEurope)
westDesease = desease(westernEurope)
for eastCases, westCases in zip(eastDesease, westDesease):
print(eastCases, westCases)

Trying to get a weighted average out of a dictionary of grades data

I am trying to return the weighted average of the student's grades based on the last definition. I have the dictionaries defined, but think my attempt to pull the numbers out is incorrect.
def Average(lst):
return sum(lst) / len(lst)
# Driver Code
lst = [1,2,3,4,5]
average = Average(lst)
print("Average of the list =", average)
def get_weighted_average(student):
return average('homework')*0.10 + average('quizzes')*0.30 + average('tests')*.60
#driver code
students = [steve, alice, tyler]
print(get_weighted_average('steve'))
How to get a weighted average out of a dictionary of grades above?
What is the primary source of your data? Text? Anyway, it looks like you have something like this in mind.
Imperative approach
1 - Your "database"
students_marks = {
'steve':{
'homework':[1,2,3,4,5],
'quizzes' :[5,4,3,2,1],
'tests' :[0,0,0,0,0],
},
'alice':{
'homework':[5,4,3,2,1],
'quizzes' :[0,0,0,0,0],
'tests' :[1,2,3,4,5],
},
}
use case:
>>> students_marks['steve']
{'homework': [1, 2, 3, 4, 5], 'quizzes': [5, 4, 3, 2, 1], 'tests': [0, 0, 0, 0, 0]}
>>> students_marks['steve']['homework']
[1, 2, 3, 4, 5]
2 - The definition of average and get_weighted_average
def average(lst):
return sum(lst)/len(lst) # Python3
#return sum(lst)/float(len(lst)) # Python2
def get_weighted_average(student_name):
student_marks = students_marks[student_name]
return round(
average(student_marks['homework'])*.1
+ average(student_marks['quizzes'])*.3
+ average(student_marks['tests'])*.6
, 2)
use case:
>>> get_weighted_average('steve')
1.2
>>> get_weighted_average('alice')
2.1
or using list
>>> students_names = ['steve', 'alice']
>>> [get_weighted_average(name) for name in students_names]
[1.2, 2.1]
or using dict
>>> {name:get_weighted_average(name) for name in students_names}
{'steve': 1.2, 'alice': 2.1}
Object-Oriented (OO) approach
All this being shown, what you want to do would probably be better done by programming in an OO manner. A quick example
class Student(object):
homeworks_weight = .1
quizzes_weight = .3
tests_weight = .6
def __init__(self, name, homeworks_marks, quizzes_marks, tests_marks):
self.name = name
self.homeworks_marks = homeworks_marks
self.quizzes_marks = quizzes_marks
self.tests_marks = tests_marks
#staticmethod
def average(marks):
return sum(marks)/len(marks)
def get_gpa(self, rd=2):
return round(
self.average(self.homeworks_marks)*self.homeworks_weight
+ average(self.quizzes_marks)*self.quizzes_weight
+ average(self.tests_marks)*self.tests_weight
, rd)
use case:
>>> steve = Student(
name = 'Steve',
homeworks_marks = [1,2,3,4,5],
quizzes_marks = [5,4,3,2,1],
tests_marks = [0,0,0,0,0]
)
>>> steve.get_gpa()
1.2
>>> steve.homeworks_marks
[1, 2, 3, 4, 5]

Extract path for each terminal node

I have a python nested dictionary structure that looks like the below.
This is a small example but I have larger examples that can have varying levels of nesting.
From this, I need to extract a list with:
One record for each terminal 'leaf' node
A string, list, or object representing the logical path leading up to that node
(e.g. 'nodeid_3: X < 0.500007 and X < 0.279907')
I've spent the larger part of this weekend trying to get something working and am realizing just how bad I am with recursion.
# Extract json string
json_string = booster.get_dump(with_stats=True, dump_format='json')[0]
# Convert to python dictionary
json.loads(json_string)
{u'children': [{u'children': [
{u'cover': 2291, u'leaf': -0.0611795, u'nodeid': 3},
{u'cover': 1779, u'leaf': -0.00965727, u'nodeid': 4}],
u'cover': 4070,
u'depth': 1,
u'gain': 265.811,
u'missing': 3,
u'no': 4,
u'nodeid': 1,
u'split': u'X',
u'split_condition': 0.279907,
u'yes': 3},
{u'cover': 3930, u'leaf': -0.0611946, u'nodeid': 2}],
u'cover': 8000,
u'depth': 0,
u'gain': 101.245,
u'missing': 1,
u'no': 2,
u'nodeid': 0,
u'split': u'X',
u'split_condition': 0.500007,
u'yes': 1}
You data structure is recursive. If a node has a children key, then we can consider that it is not terminal.
To analyze your data, you need a recursive function which keeps track of the ancestors (the path).
I would implement this like that:
def find_path(obj, path=None):
path = path or []
if 'children' in obj:
child_obj = {k: v for k, v in obj.items()
if k in ['nodeid', 'split_condition']}
child_path = path + [child_obj]
children = obj['children']
for child in children:
find_path(child, child_path)
else:
pprint.pprint((obj, path))
If you call:
find_path(data)
You get 3 results:
({'cover': 2291, 'leaf': -0.0611795, 'nodeid': 3},
[{'nodeid': 0, 'split_condition': 0.500007},
{'nodeid': 1, 'split_condition': 0.279907}])
({'cover': 1779, 'leaf': -0.00965727, 'nodeid': 4},
[{'nodeid': 0, 'split_condition': 0.500007},
{'nodeid': 1, 'split_condition': 0.279907}])
({'cover': 3930, 'leaf': -0.0611946, 'nodeid': 2},
[{'nodeid': 0, 'split_condition': 0.500007}])
Of course, you can replace the call to pprint.pprint() by a yield to turn this function into a generator:
def iter_path(obj, path=None):
path = path or []
if 'children' in obj:
child_obj = {k: v for k, v in obj.items()
if k in ['nodeid', 'split_condition']}
child_path = path + [child_obj]
children = obj['children']
for child in children:
# for o, p in iteration_path(child, child_path):
# yield o, p
yield from iter_path(child, child_path)
else:
yield obj, path
Note the usage of yield from for the recursive call. You use this generator like below:
for obj, path in iter_path(data):
pprint.pprint((obj, path))
You can also change the way child_obj object is build to match your needs.
To keep the order of objects: reverse the if condition: if 'children' not in obj: ….

Categories

Resources