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.
Related
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!
I have been struggling to extract sub dictionaries where the value is "0" from a list of dictionaries and add them to temporary dictionaries.
I tried this:
new_users = [{'user1':{'book1':'0', 'book2':'4', 'book3':'1'}},{'user2':{'book1':'5', 'book2':'1', 'book3':'0'}}]
def approachA():
for data in new_users: # new_users is a list of nested dictionaries
if data == '0':
print("found 0")
keys = data.keys()
for key in keys:
if key == '0':
key.pop() # tried to deleted delete the elements at first
It did not work for some reason, and I have been trying to do it for 2 hours so please do not ask questions not related to the problem.
This is a simple version of what I am trying to do:
[{'user1':{'book1':'0', 'book2':'4', 'book3':'1'}},{'user2':{'book1':'5', 'book2':'1', 'book3':'0'}}] -> [{'user1':{'book1':'0'}}, {'user2':{'book3':'0'}}]
So basically the keys with value "0" get copied to a temp list of dictionaries.
As I mentioned in a comment I'm not sure this will solve your problem, but based on the sample transformation you gave, here's one way to achieve it:
LIST_IN = [{"name": {"book1": "0", "book2": "1", "book3": "0"}}]
def proccess(list_in):
result = []
for this_dict in list_in:
for key in this_dict["name"]:
if this_dict["name"][key] == "0":
result.append({key: this_dict["name"][key]})
return result
print(proccess(LIST_IN))
This should accomplish the "sample" snippet. Please give some additional details if this is not what you were trying.
def solve_nested(nested_dict: list) -> list:
result = list()
for dictionary in nested_dict:
for k, v in dictionary.items():
for _k, _v in v.items():
if _v == '0':
result.append({_k: _v})
return result
if __name__ == '__main__':
print(solve_nested([{"name": {"book1": "0", "book2": "1", "book3": "0"}}]))
If you're interested in recursion, the below example ought to get you going:
# d_xy => x = nest level
# y = dictionary item in nest level x
d = {'d_00' : {'d_10' : {'d_20' : 0,
'd_21' : 43,
'd_22' : 12},
'd_11' : 4,
'd_12' : 0,
'd_13' : 1},
'd_01' : 0,
'd_02' : {'d_14' : {'d_23' : 0,
'd_24' : 1,
'd_25' : 0},
'd_15' : 4,
'd_16' : {'d_26' : 0,
'd_27' : {'d_30' : 3,
'd_31' : 0,
'd_32' : {'d_40' : 0},
'd_33' : 0},
'd_28' : 1},
'd_17' : 0}}
important_items = []
def get_0_key_values(dic):
for key in dic:
if type(dic[key]) == dict:
get_0_key_values(dic[key])
else:
if dic[key] == 0:
important_items.append({key : dic[key]})
get_0_key_values(d)
print(important_items)
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]
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: ….
I have result set of rows in a database that all relate to each other through a parent child relationship
Each row is represented as follows objectid, id, parent, child, name, level so when I read an example from the database in my program it looks like this
Organization1
Component1
Department1
Sections1
Sections2
Department2
Sections3
Component2
Department3
Sections4
Sections5
Department4
Sections6
Where Organizations has many departments and departments has many Components and Components has many sections
my code thus far looks like this and that works but I need to put it into json format and the json format has to look like the below
for v in result:
level = v[5]
child = v[3]
parent = v[2]
if level == 0:
OrgDic['InstID'] = v[4]
OrgDic['Child'] = v[3]
OrgDic['Parent'] = v[2]
Organizations.append(InstDic)
OrgDic = {}
if level == 1:
ComponentsDic['CollegeID'] = v[4]
ComponentsDic['Child'] = v[3]
ComponentsDic['Parent'] = v[2]
Components.append(CollegeDic)
ComponentsDic = {}
if level == 2:
DepartmentDic['DepartmentID'] = v[4]
DepartmentDic['Child'] = v[3]
DepartmentDic['Parent'] = v[2]
Departments.append(DepartmentDic)
DepartmentDic = {}
if level == 3:
SectionDic['SubjectID'] = v[4]
SectionDic['Child'] = v[3]
SectionDic['Parent'] = v[2]
Sections.append(SubjectDic)
SectionDic = {}
for w in :
print w['Organization']
for x in Components:
if w['Child'] == x['Parent']:
print x['Components']
for y in Departments:
if x['Child'] == y['Parent']:
print y['Deparments']
for z in Sections:
if y['Child'] == z['Parent']:
print z['Sections']
JSON FORMAT
{
"Eff_Date": "08/02/2013",
"Tree":
[
{
"OrganizationID": "Organization1",
"Components":
[
{"ComponentID": "Component1",
"Departments":
[
{"DepartmentID": "Dep1",
"Sections":
[
{"SectionID": "Section1"},
{"SectionID": "Section2"}
]},
{"DepartmentID": "Dep2",
"Sections":
[
{"SectionID": "Section3"}
]}
]}
]
}
basically, all you have to do is dump the json after your first snippet (given that snippet does correctly create the tree you exposed, I did not thoroughly check it, but it looks coherent):
import json
print json.dumps({"Eff_Date": "08/02/2013", "Tree":Organizations})
and tada!
I was able to do it the following way
data[]
data.append([-1, 0 ,"name1", 0])
data.append([0,1, "name2", 1])
data.append([1, 2, "name3", 1])
data.append([2 ,3, "name4", 2])
data.append([2 ,4, "name5" ,2])
data.append([1 ,5, "name6", 2])
data.append([5, 6, "name7", 3])
data.append([5, 7, "name8",1])
data.append([5, 7, "name9",2])
def listToDict(input):
root = {}
lookup = {}
for parent_id, id, name, attr in input:
if parent_id == -1:
root['name'] = name;
lookup[id] = root
else:
node = {'name': name}
lookup[parent_id].setdefault('children', []).append(node)
lookup[id] = node
return root
result = listToDict(data)
print result
print json.dumps(result)
In my case my data was a result set from a database so I had to loop through it as follows
for v in result:
values = [v[2], v[3], v[4], v[5]]
pc.append(values)