Related
I want to merge list of dictionary provided below with unique channel and zrepcode.
sample input:
[
{
"channel": 1,
"zrepcode": "123456",
"turn": 7833.9
},
{
"channel": 1,
"zrepcode": "123456",
"pipeline": 324
},
{
"channel": 1,
"zrepcode": "123456",
"inv_bal": 941.16
},
{
"channel": 1,
"zrepcode": "123456",
"display": 341
},
{
"channel": 3,
"zrepcode": "123456",
"display": 941.16
},
{
"channel": 3,
"zrepcode": "123456",
"turn": 7935.01
},
{
"channel": 3,
"zrepcode": "123456",
"pipeline": 0
},
{
"channel": 3,
"zrepcode": "123456",
"inv_bal": 341
},
{
"channel": 3,
"zrepcode": "789789",
"display": 941.16
},
{
"channel": 3,
"zrepcode": "789789",
"turn": 7935.01
},
{
"channel": 3,
"zrepcode": "789789",
"pipeline": 0
},
{
"channel": 3,
"zrepcode": "789789",
"inv_bal": 341
}
]
Sample output:
[
{'channel': 1, 'zrepcode': '123456', 'turn': 7833.9, 'pipeline': 324.0,'display': 341,'inv_bal': 941.16},
{'channel': 3, 'zrepcode': '123456', 'turn': 7935.01, 'pipeline': 0.0, 'display': 941.16, 'inv_bal': 341.0},
{'channel': 3, 'zrepcode': '789789', 'turn': 7935.01, 'pipeline': 0.0, 'display': 941.16, 'inv_bal': 341.0}
]
Easily solved with our good friend collections.defaultdict:
import collections
by_key = collections.defaultdict(dict)
for datum in data: # data is the list of dicts from the post
key = (datum.get("channel"), datum.get("zrepcode")) # form the key tuple
by_key[key].update(datum) # update the defaultdict by the key tuple
print(list(by_key.values()))
This outputs
[
{'channel': 1, 'zrepcode': '123456', 'turn': 7833.9, 'pipeline': 324, 'inv_bal': 941.16, 'display': 341},
{'channel': 3, 'zrepcode': '123456', 'display': 941.16, 'turn': 7935.01, 'pipeline': 0, 'inv_bal': 341},
{'channel': 3, 'zrepcode': '789789', 'display': 941.16, 'turn': 7935.01, 'pipeline': 0, 'inv_bal': 341},
]
i have my sample data as
b = [{"id": 1, "name": {"d_name": "miranda", "ingredient": "orange"}, "score": 1.123},
{"id": 20, "name": {"d_name": "limca", "ingredient": "lime"}, "score": 4.231},
{"id": 3, "name": {"d_name": "coke", "ingredient": "water"}, "score": 4.231},
{"id": 2, "name": {"d_name": "fanta", "ingredient": "water"}, "score": 4.231},
{"id": 3, "name": {"d_name": "dew", "ingredient": "water & sugar"}, "score": 2.231}]
i need to sort such that score ASC, name DESC, id ASC (by relational db notation).
So far, i have implemented
def sort_func(e):
return (e['score'], e['name']['d_name'], e['id'])
a = b.sort(key=sort_func, reverse=False)
This works for score ASC, name ASC, id ASC.
but for score ASC, name DESC, id ASC if i try to sort by name DESC it throws error. because of unary - error in -e['name']['d_name'].
How can i approach this problem, from here ? Thanks,
Edit 1:
i need to make this dynamic such that there can be case such as e['name'['d_name'] ASC, e['name']['ingredient'] DESC. How can i handle this type of dynamic behaviour ?
You can sort by -score, name, -id with reverse=True:
from pprint import pprint
b = [
{
"id": 1,
"name": {"d_name": "miranda", "ingredient": "orange"},
"score": 1.123,
},
{
"id": 20,
"name": {"d_name": "limca", "ingredient": "lime"},
"score": 4.231,
},
{
"id": 3,
"name": {"d_name": "coke", "ingredient": "water"},
"score": 4.231,
},
{
"id": 2,
"name": {"d_name": "fanta", "ingredient": "water"},
"score": 4.231,
},
{
"id": 3,
"name": {"d_name": "dew", "ingredient": "water & sugar"},
"score": 2.231,
},
]
pprint(
sorted(
b,
key=lambda k: (-k["score"], k["name"]["d_name"], -k["id"]),
reverse=True,
)
)
Prints:
[{'id': 1,
'name': {'d_name': 'miranda', 'ingredient': 'orange'},
'score': 1.123},
{'id': 3,
'name': {'d_name': 'dew', 'ingredient': 'water & sugar'},
'score': 2.231},
{'id': 20, 'name': {'d_name': 'limca', 'ingredient': 'lime'}, 'score': 4.231},
{'id': 2, 'name': {'d_name': 'fanta', 'ingredient': 'water'}, 'score': 4.231},
{'id': 3, 'name': {'d_name': 'coke', 'ingredient': 'water'}, 'score': 4.231}]
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
class Order_ListAPIView(APIView):
def get(self,request,format=None):
totalData=[]
if request.method == 'GET':
cur,conn = connection()
order_query = ''' SELECT * FROM orders '''
order_detail_query = ''' SELECT * FROM order_details '''
user_query = ''' SELECT * FROM users '''
with conn.cursor(MySQLdb.cursors.DictCursor) as cursor:
cursor.execute(order_detail_query)
order_detail_result = cursor.fetchall()
order_detail_data = list(order_detail_result)
# print(order_detail_data)
cursor.execute(order_query)
order_result = cursor.fetchall()
order_data = list(order_result)
cursor.execute(user_query)
user_result = cursor.fetchall()
user_data = list(user_result)
dic = {}
def merge_order_data_and_detail(order_data, order_detail_data):
for d in order_detail_data:
if d['order_id'] not in dic:
dic[d['order_id']] = []
dic[d['order_id']].append(d)
for o in order_data:
if o['order_id'] in dic:
o['order_detail_data'] = dic[o['order_id']]
merge_order_data_and_detail(order_data, order_detail_data)
# totalData.append({"order_data":order_data, })
return Response({"order_data":order_data, "user_data":user_data},status=status.HTTP_200_OK)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
Output:
{
"order_data": [
{
"order_id": 1,
"payment_method_id": 1,
"delivery_id": 2,
"user_id": 3,
"txnid": "584ffb7fd622eca10a6d",
"order_no": "1-1583152683-0005",
"order_total": 1.0,
"payment_status": "Paid",
"payuMoneyId": "306043618",
"mihpayid": "9956109007",
"order_detail_data": [
{
"order_detail_id": 1,
"order_id": 1,
"user_id": 3,
"qty": 1,
"product_price": 1.0,
"order_item_status": "Placed",
"feedback": ""
}
]
},
{
"order_id": 2,
"payment_method_id": 2,
"delivery_id": 2,
"user_id": 2,
"txnid": "",
"order_no": "1-1583152785-0010",
"order_total": 1.0,
"payment_status": "Unpaid",
"payuMoneyId": "",
"mihpayid": "",
"order_detail_data": [
{
"order_detail_id": 2,
"order_id": 2,
"user_id": 2,
"qty": 1,
"product_price": 1.0,
"order_item_status": "Cancelled",
"feedback": "0"
}
]
},
{
"order_id": 3,
"payment_method_id": 1,
"delivery_id": 2,
"user_id": 1,
"txnid": "83e066ca75437f433343d05b0",
"order_no": "2-1583152964-0019",
"order_total": 2.0,
"payment_status": "Paid",
"payuMoneyId": "306044826",
"mihpayid": "9956136979",
"order_detail_data": [
{
"order_detail_id": 3,
"order_id": 3,
"user_id": 1,
"qty": 2,
"product_price": 1.0,
"order_item_status": "Placed",
"feedback": ""
}
]
},
],
"user_data": [
{
"user_id": 1,
"role": 0,
"created_by": 0,
"group_in": 0,
"name": "Deebaco",
"email": "singh.deeba#gmail.com",
"mobile": "",
"password": "",
"image": "",
"last_login": null,
"rand": "",
"opened": 0,
"auth_id": "114025425174039",
"auth_platform": "Google",
"created_datetime": "2020-03-02T17:54:28",
"updated_datetime": "2020-03-02T17:54:28",
"status": "Active"
},
{
"user_id": 2,
"role": 0,
"created_by": 0,
"group_in": 0,
"name": "Kriti Mathur",
"email": "mathurkriti#gmail.com",
"mobile": "",
"password": "",
"image": "",
"last_login": null,
"rand": "",
"opened": 0,
"auth_id": "111445960345755",
"auth_platform": "Google",
"created_datetime": "2020-03-02T18:02:24",
"updated_datetime": "2020-03-02T18:02:24",
"status": "Active"
},
{
"user_id": 3,
"role": 0,
"created_by": 0,
"group_in": 0,
"name": "Sakshi Swarnkar",
"email": "sakshi#gmail.com",
"mobile": "",
"password": "",
"image": "",
"last_login": null,
"rand": "",
"opened": 0,
"auth_id": "117543975857",
"auth_platform": "Google",
"created_datetime": "2020-03-02T18:02:24",
"updated_datetime": "2020-03-02T18:02:24",
"status": "Active"
},
]
}
what i want is like this below: get name replace of user_id.
{
"order_data": [
{
"order_id": 1,
"payment_method_id": 1,
"delivery_id": 2,
"name": "Sakshi Swarnkar",
"txnid": "584ffb7fd622eca10a6d",
"order_no": "1-1583152683-0005",
"order_total": 1.0,
"payment_status": "Paid",
"payuMoneyId": "306043618",
"mihpayid": "9956109007",
"order_detail_data": [
{
"order_detail_id": 1,
"order_id": 1,
"name": "Sakshi Swarnkar",
"qty": 1,
"product_price": 1.0,
"order_item_status": "Placed",
"feedback": ""
}
]
},
{
"order_id": 2,
"payment_method_id": 2,
"delivery_id": 2,
"name": "Kriti Mathur",
"txnid": "",
"order_no": "1-1583152785-0010",
"order_total": 1.0,
"payment_status": "Unpaid",
"payuMoneyId": "",
"mihpayid": "",
"order_detail_data": [
{
"order_detail_id": 2,
"order_id": 2,
"name": "Kriti Mathur",
"qty": 1,
"product_price": 1.0,
"order_item_status": "Cancelled",
"feedback": "0"
}
]
},
{
"order_id": 3,
"payment_method_id": 1,
"delivery_id": 2,
"name": "Deebaco",
"txnid": "83e066ca75437f433343d05b0",
"order_no": "2-1583152964-0019",
"order_total": 2.0,
"payment_status": "Paid",
"payuMoneyId": "306044826",
"mihpayid": "9956136979",
"order_detail_data": [
{
"order_detail_id": 3,
"order_id": 3,
"name": "Deebaco",
"qty": 2,
"product_price": 1.0,
"order_item_status": "Placed",
"feedback": ""
}
]
},
],
i am direct fetching data using raw query from databases instead of
ORM. i want to get user-name replace of user_id.
i am trying to solve this problem, but i didn't get any possible answer which could solve this problem. It would be great if anyone could help me out for what i am looking for. Advance thank you so much!.
You will need to change the sql query of: order_query = ''' SELECT * FROM orders '''
Your sql query will need a join
SELECT users.name,order.* from order left join users on order.user_id = users.user_id
It will not be exactly what you expect because I don't have all the information and I'm making assumptions about your DB, but this should work after you reworked it slightly
This question already has answers here:
Python: create a nested dictionary from a list of parent child values
(3 answers)
Closed 3 years ago.
I have a list of dictionaries that I got from the database in parent-child relationship:
data = [
{"id":1, "parent_id": 0, "name": "Wood", "price": 0},
{"id":2, "parent_id": 1, "name": "Mango", "price": 18},
{"id":3, "parent_id": 2, "name": "Table", "price": 342},
{"id":4, "parent_id": 2, "name": "Box", "price": 340},
{"id":5, "parent_id": 4, "name": "Pencil", "price": 240},
{"id":6, "parent_id": 0, "name": "Electronic", "price": 20},
{"id":7, "parent_id": 6, "name": "TV", "price": 350},
{"id":8, "parent_id": 6, "name": "Mobile", "price": 300},
{"id":9, "parent_id": 8, "name": "Iphone", "price": 0},
{"id":10, "parent_id": 9, "name": "Iphone 10", "price": 400}
]
I want to convert it to a nested dictionary such as
[ { "id": 1, "parent_id": 0, "name": "Wood", "price": 0, "children": [ { "id": 2, "parent_id": 1, "name": "Mango", "price": 18, "children": [ { "id": 3, "parent_id": 2, "name": "Table", "price": 342 }, { "id": 4, "parent_id": 2, "name": "Box", "price": 340, "children": [ { "id": 5, "parent_id": 4, "name": "Pencil", "price": 240 } ] } ] } ] }, { "id": 6, "parent_id": 0, "name": "Electronic", "price": 20, "children": [ { "id": 7, "parent_id": 6, "name": "TV", "price": 350 }, { "id": 8, "parent_id": 6, "name": "Mobile", "price": 300, "children": [ { "id": 9, "parent_id": 8, "name": "Iphone", "price": 0, "children": [ { "id": 10, "parent_id": 9, "name": "Iphone 10", "price": 400 } ] } ] } ] } ]
You can do this recursively, starting from the root nodes (where parent_id = 0) going downwards. But before your recursive calls, you can group nodes by their parent_id so that accessing them in each recursive call can be done in constant time:
levels = {}
for n in data:
levels.setdefault(n['parent_id'], []).append(n)
def build_tree(parent_id=0):
nodes = [dict(n) for n in levels.get(parent_id, [])]
for n in nodes:
children = build_tree(n['id'])
if children: n['children'] = children
return nodes
tree = build_tree()
print(tree)
Output
[{'id': 1, 'parent_id': 0, 'name': 'Wood', 'price': 0, 'children': [{'id': 2, 'parent_id': 1, 'name': 'Mango', 'price': 18, 'children': [{'id': 3, 'parent_id': 2, 'name': 'Table', 'price': 342}, {'id': 4, 'parent_id': 2, 'name': 'Box', 'price': 340, 'children': [{'id': 5, 'parent_id': 4, 'name': 'Pencil', 'price': 240}]}]}]}, {'id': 6, 'parent_id': 0, 'name': 'Electronic', 'price': 20, 'children': [{'id': 7, 'parent_id': 6, 'name': 'TV', 'price': 350}, {'id': 8, 'parent_id': 6, 'name': 'Mobile', 'price': 300, 'children': [{'id': 9, 'parent_id': 8, 'name': 'Iphone', 'price': 0,'children': [{'id': 10, 'parent_id': 9, 'name': 'Iphone 10', 'price': 400}]}]}]}]
Code is documented inline. Ignoring the corner cases like circular relations etc.
# Actual Data
data = [
{"id":1, "parent_id": 0, "name": "Wood", "price": 0},
{"id":2, "parent_id": 1, "name": "Mango", "price": 18},
{"id":3, "parent_id": 2, "name": "Table", "price": 342},
{"id":4, "parent_id": 2, "name": "Box", "price": 340},
{"id":5, "parent_id": 4, "name": "Pencil", "price": 240},
{"id":6, "parent_id": 0, "name": "Electronic", "price": 20},
{"id":7, "parent_id": 6, "name": "TV", "price": 350},
{"id":8, "parent_id": 6, "name": "Mobile", "price": 300},
{"id":9, "parent_id": 8, "name": "Iphone", "price": 0},
{"id":10, "parent_id": 9, "name": "Iphone 10", "price": 400}
]
# Create Parent -> child links using dictonary
data_dict = { r['id'] : r for r in data}
for r in data:
if r['parent_id'] in data_dict:
parent = data_dict[r['parent_id']]
if 'children' not in parent:
parent['children'] = []
parent['children'].append(r)
# Helper function to get all the id's associated with a parent
def get_all_ids(r):
l = list()
l.append(r['id'])
if 'children' in r:
for c in r['children']:
l.extend(get_all_ids(c))
return l
# Trimp the results to have a id only once
ids = set(data_dict.keys())
result = []
for r in data_dict.values():
the_ids = set(get_all_ids(r))
if ids.intersection(the_ids):
ids = ids.difference(the_ids)
result.append(r)
print (result)
Output:
[{'id': 1, 'parent_id': 0, 'name': 'Wood', 'price': 0, 'children': [{'id': 2, 'parent_id': 1, 'name': 'Mango', 'price': 18, 'children': [{'id': 3, 'parent_id': 2, 'name': 'Table', 'price': 342}, {'id': 4, 'parent_id': 2, 'name': 'Box', 'price': 340, 'children': [{'id': 5, 'parent_id': 4, 'name': 'Pencil', 'price': 240}]}]}]}, {'id': 6, 'parent_id': 0, 'name': 'Electronic', 'price': 20, 'children': [{'id': 7, 'parent_id': 6, 'name': 'TV', 'price': 350}, {'id': 8, 'parent_id': 6, 'name': 'Mobile', 'price': 300, 'children': [{'id': 9, 'parent_id': 8, 'name': 'Iphone', 'price': 0, 'children': [{'id': 10, 'parent_id': 9, 'name': 'Iphone 10', 'price': 400}]}]}]}]
I worked out a VERY SHORT solution, I believe it isn't the most efficient algorithm, but it does the job, will need a hell of optimization to work on very large data sets.
for i in range(len(data)-1, -1, -1):
data[i]["children"] = [child for child in data if child["parent_id"] == data[i]["id"]]
for child in data[i]["children"]:
data.remove(child)
Here is the complete explanation:
data = [
{"id":1, "parent_id": 0, "name": "Wood", "price": 0},
{"id":2, "parent_id": 1, "name": "Mango", "price": 18},
{"id":3, "parent_id": 2, "name": "Table", "price": 342},
{"id":4, "parent_id": 2, "name": "Box", "price": 340},
{"id":5, "parent_id": 4, "name": "Pencil", "price": 240},
{"id":6, "parent_id": 0, "name": "Electronic", "price": 20},
{"id":7, "parent_id": 6, "name": "TV", "price": 350},
{"id":8, "parent_id": 6, "name": "Mobile", "price": 300},
{"id":9, "parent_id": 8, "name": "Iphone", "price": 0},
{"id":10, "parent_id": 9, "name": "Iphone 10", "price": 400}
]
# Looping backwards,placing the lowest child
# into the next parent in the heirarchy
for i in range(len(data)-1, -1, -1):
# Create a dict key for the current parent in the loop called "children"
# and assign to it a list comprehension that loops over all items in the data
# to get the elements which have a parent_id equivalent to our current element's id
data[i]["children"] = [child for child in data if child["parent_id"] == data[i]["id"]]
# since the child is placed inside our its parent already, we will
# remove it from its actual position in the data
for child in data[i]["children"]:
data.remove(child)
# print the new data structure
print(data)
And here is the output:
[{'id': 1, 'parent_id': 0, 'name': 'Wood', 'price': 0, 'children': [{'id': 2, 'parent_id': 1, 'name': 'Mango', 'price': 18, 'children': [{'id': 3, 'parent_id': 2, 'name': 'Table', 'price': 342, 'children': []}, {'id': 4, 'parent_id': 2, 'name': 'Box', 'price': 340, 'children': [{'id': 5, 'parent_id': 4, 'name': 'Pencil', 'price': 240, 'children': []}]}]}]}, {'id': 6, 'parent_id': 0, 'name': 'Electronic', 'price': 20, 'children': [{'id': 7, 'parent_id': 6, 'name': 'TV', 'price': 350, 'children': []}, {'id': 8, 'parent_id': 6, 'name': 'Mobile', 'price': 300, 'children': [{'id': 9, 'parent_id': 8, 'name': 'Iphone', 'price': 0, 'children': [{'id': 10, 'parent_id': 9, 'name': 'Iphone 10', 'price': 400, 'children': []}]}]}]}]
I'm feeding a function a string, which reads the string char by char. Based on the char being worked on, a JSON template is called from a dictionary, edited slightly and saved to a final dictionary, which will be parsed to JSON and saved.
The problem is that this template dictionary should stay constant, but it doesn't. Somehow, the values I write to the intermediate variable gets saved to the original template dictionary, messing up the subsequent data I'm trying to save.
Am I missing some basic concept of the dictionary? This is my first time working with dictionaries to such an extent so I wouldn't even be surprised.
The template dictionary:
self.map_legend = {"#": {"Id": 100, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Wall", "PlayerNumber": 0},
"-": {"Id": 200, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Shield", "PlayerNumber": 0},
"x": {"Id": 300, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Alien", "PlayerNumber": 0},
"|": {"Id": 400, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "AlienBullet", "PlayerNumber": 0},
"!": {"Id": 500, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Missile", "PlayerNumber": 0},
"i": {"Id": 500, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Missile", "PlayerNumber": 1},
"M": {"Id": 600, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "MissileController", "PlayerNumber": 0},
"X": {"Id": 700, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "AlienFactory", "PlayerNumber": 0},
"A": {"Id": 800, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "Ship", "PlayerNumber": 0},
"V": {"Id": 800, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "Ship", "PlayerNumber": 1},
" ": {"Id": 900, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Space", "PlayerNumber": 0}}
The problem code:
for char in self.initial_game_map:
if char != "\n":
element = self.map_legend[char]
self.id_counters[char] += 1
element["Id"] = self.id_counters[char] + element["Id"]
element["Alive"] = True
element["X"] = char_counter % self.state_json["Map"]["Height"]
element["Y"] = char_counter / self.state_json["Map"]["Height"]
print self.map_legend[char]
print element
row.append(element)
element = {}
char_counter += 1
else:
self.state_json["Map"]["Rows"].append(row)
row = []
Some output:
V
{'Width': 3, 'PlayerNumber': 1, 'Y': 1, 'X': 2, 'Type': 'Ship', 'Id': 801, 'Alive': True, 'Height': 1}
{'Width': 3, 'PlayerNumber': 1, 'Y': 1, 'X': 2, 'Type': 'Ship', 'Id': 801, 'Alive': True, 'Height': 1}
#
{'Width': 1, 'PlayerNumber': 0, 'Y': 0, 'X': 18, 'Type': 'Wall', 'Id': 103, 'Alive': True, 'Height': 1}
{'Width': 1, 'PlayerNumber': 0, 'Y': 0, 'X': 18, 'Type': 'Wall', 'Id': 103, 'Alive': True, 'Height': 1}
the element variable is behaving as its supposed to, but you can see that self.map_legend assumes the value of element for some reason after element is changed, which is NOT what I want. What's going on?
element and self.map_legend[char] point to the same dictionary and thus if you update element you will update the values of the dictionary self.map_legend[char]. You seem to want a copy so use:
element = self.map_legend[char].copy()
Reference in the python documentation: https://docs.python.org/2/library/copy.html. As the dictionaries are shallow you don't need .deepcopy()
You need to deepcopy the dictionary, else the original will get modified.
from copy import deepcopy
element = deepcopy(self.map_legend[char])