Entries added to dictionary get overwritten - python

There is a dictionary initialized, serializer provides some data and adding to a nested array is made by iterating list of items:
list = {"shopping_list": []}
item = {}
count = 0
stuff = json.loads(serializer.data["stuff_file"])
for s in stuff:
item["level"] = count
item["position"] = count * 10
item["item_name"] = s["name"]
list["shopping_list"].append(item)
count += 1
But instead of receiving a list of unique items (expected the append method to do that), I get the list with proper count of items, but all previous ones are overwritten by the most recent one, like:
{
"shopping_list": [
{
"level": 2,
"position": 20,
"item_name": "Bronze Badge"
},
{
"level": 2,
"position": 20,
"item_name": "Bronze Badge"
},
{
"level": 2,
"position": 20,
"item_name": "Bronze Badge"
}
]
}
How should I write to the list to have all of the items unique, e.g.:
{
"shopping_list": [
{
"level": 0,
"position": 0,
"item_name": "Gold Badge"
},
{
"level": 1,
"position": 10,
"item_name": "Silver Badge"
},
{
"level": 2,
"position": 20,
"item_name": "Bronze Badge"
}
]
}
?

Instead of creating the variable outside the loop, create item inside it:
list = {"shopping_list": []}
count = 0
stuff = [{"name": "Gold Badge"}, {"name": "Silver Badge"}, {"name": "Bronze Badge"}]
for s in stuff:
item = {}
item["level"] = count
item["position"] = count * 10
item["item_name"] = s["name"]
list["shopping_list"].append(item)
count += 1
print(list)
Output:
{'shopping_list': [{'level': 0, 'position': 0, 'item_name': 'Gold Badge'}, {'level': 1, 'position': 10, 'item_name': 'Silver Badge'},{'level': 2, 'position': 20, 'item_name': 'Bronze Badge'}]}
As #DeepSpace pointed out, you can also use a dictionary literal:
for s in stuff:
list["shopping_list"].append({'level': count, 'position': count * 10, 'item_name': s['name']})
count += 1
In fact, you could get rid of the count variable and do this as well:
for count, s in enumerate(stuff):
list["shopping_list"].append({'level': count, 'position': count * 10, 'item_name': s['name']})

Related

how to get a nested data from Concatenate values with same keys in a list of dictionaries?

I have all_writing_test_name_data
all_writing_test_name_data=
[
{
"id": 1,
"book_name": Math,
"writing_test_description": "string",
"subject_id": 1,
"book_id": 2,
"writing_test": "string"
},
{
"id": 2,
"book_name": Math-1,
"writing_test_description": "string-1",
"subject_id": 1,
"book_id": 2,
"writing_test": "string-1"
}
]
and I want to Concatenate all_writing_test_name_data like this
[
{
"subject_id": 1,
"writing_items": [
{
"id": 1,
"book_name": Math,
"writing_test_description": "string",
"book_id": 2,
"writing_test": "string"
},
{
"id": 2,
"book_name": Math-1,
"writing_test_description": "string-1",
"book_id": 2,
"writing_test": "string-1"
}
]
}
]
i have tried this but i think there is some lacking in the code for this i can't get the desire data
x=all_writing_test_name_data
# printing original list
print("The original list is : " + str(x))
import operator
from functools import reduce
all_keys = reduce(operator.or_, (d.keys() for d in x))
bar = {key: [d.get(key) for d in x] for key in all_keys}
print('bar',bar['writing_test']+bar['writing_test_description'])
from collections import Counter
result = Counter()
for d in x:
result[d['writing_test']] = d['writing_test']
result[d['writing_test_description']] = d['writing_test_description']
print(result)
z=bar['writing_test']+bar['writing_test_description']
print bar
but I can't get my desire data. how can i get the exact same data,what is the mistake
You can group the input data by the subject_id property of each dict, then re-format that data into the value you want:
from collections import defaultdict
groups = defaultdict(list)
for test in all_writing_test_name_data:
subject_id = test.pop('subject_id')
groups[subject_id].append(test)
result = [ { 'subject_id' : k, 'writing_items' : v } for k, v in groups.items() ]
Output:
[
{
"subject_id": 1,
"writing_items": [
{
"id": 1,
"book_name": "Math",
"writing_test_description": "string",
"book_id": 2,
"writing_test": "string"
},
{
"id": 2,
"book_name": "Math-1",
"writing_test_description": "string-1",
"book_id": 2,
"writing_test": "string-1"
}
]
}
]
Note that this will alter the value of all_writing_test_name_data (due to the test.pop()). If this is not desired, add
test = test.copy()
prior to the pop.

How to extract JSON from a nested JSON file?

I am calling an API and getting a response like the below.
{
"status": 200,
"errmsg": "OK",
"data": {
"total": 12,
"items": [{
"id": 11,
"name": "BBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChain": {
"inAlerting": false,
"throttlingAlerts": 20,
"enableThrottling": true,
"name": "Example123",
"destination": [],
"description": "",
"ccdestination": [],
"id": 3,
"throttlingPeriod": 10
}
},
{
"id": 21,
"name": "CNBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChain": {
"inAlerting": false,
"throttlingAlerts": 20,
"enableThrottling": true,
"name": "Example456",
"destination": [],
"description": "",
"ccdestination": [],
"id": 3,
"throttlingPeriod": 10
}
}
]
}
}
I need to clean-up this JSON a bit and produce a simple JSON like below where escalatingChainName is the name in the escalatingChain list so that I can write this into a CSV file.
{
"items": [{
"id": 11,
"name": "BBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChainName": "Example123"
},
{
"id": 21,
"name": "CNBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChainName": "Example456"
}
]
}
Is there a JSON function that I can use to copy only the necessary key-value or nested key-values to a new JSON object?
With the below code, I am able to get the details list.
json_response = response.json()
items = json_response['data']
details = items['items']
I can print individual list items using
for x in details:
print(x)
How do I take it from here to pull only the necessary fields like id, name, priority and the name from escalatingchain to create a new list or JSON?
There is no existing function that will do what you want, so you'll need to write one. Fortunately that's not too hard in this case — basically you just create a list of new items by extracting the pieces of data you want from the existing ones.
import json
json_response = """\
{
"status": 200,
"errmsg": "OK",
"data": {
"total": 12,
"items": [{
"id": 11,
"name": "BBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChain": {
"inAlerting": false,
"throttlingAlerts": 20,
"enableThrottling": true,
"name": "Example123",
"destination": [],
"description": "",
"ccdestination": [],
"id": 3,
"throttlingPeriod": 10
}
},
{
"id": 21,
"name": "CNBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChain": {
"inAlerting": false,
"throttlingAlerts": 20,
"enableThrottling": true,
"name": "Example456",
"destination": [],
"description": "",
"ccdestination": [],
"id": 3,
"throttlingPeriod": 10
}
}
]
}
}
"""
response = json.loads(json_response)
cleaned = []
for item in response['data']['items']:
cleaned.append({'id': item['id'],
'name': item['name'],
'priority': item['priority'],
'levelStr': item['levelStr'],
'escalatingChainId': item['escalatingChainId'],
'escalatingChainName': item['escalatingChain']['name']})
print('cleaned:')
print(json.dumps(cleaned, indent=4))
You can try:
data = {
"status": 200,
"errmsg": "OK",
"data": {
"total": 12,
"items": [{
"id": 11,
"name": "BBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChain": {
"inAlerting": False,
"throttlingAlerts": 20,
"enableThrottling": True,
"name": "Example123",
"destination": [],
"description": "",
"ccdestination": [],
"id": 3,
"throttlingPeriod": 10
}
},
{
"id": 21,
"name": "CNBC",
"priority": 4,
"levelStr": "All",
"escalatingChainId": 3,
"escalatingChain": {
"inAlerting": False,
"throttlingAlerts": 20,
"enableThrottling": True,
"name": "Example456",
"destination": [],
"description": "",
"ccdestination": [],
"id": 3,
"throttlingPeriod": 10
}
}
]
}
}
for single_item in data["data"]["items"]:
print(single_item["id"])
print(single_item["name"])
print(single_item["priority"])
print(single_item["levelStr"])
print(single_item["escalatingChain"]["inAlerting"])
# and so on
Two ways of approaching this depending on whether your dealing with a variable or .json file using python list and dictionary comprehension:
Where data variable of type dictionary (nested) already defined:
# keys you want
to_keep = ['id', 'name', 'priority', 'levelStr', 'escalatingChainId',
'escalatingChainName']
new_data = [{k:v for k,v in low_dict.items() if k in to_keep}
for low_dict in data['data']['items']]
# where item is dictionary at lowest level
escalations = [{v+'Name':k[v]['name']} for k in data['data']['items']
for v in k if type(k[v])==dict]
# merge both lists of python dictionaries to produce flattened list of dictionaries
new_data = [{**new,**escl} for new,escl in zip(new_data,escalations)]
Or (and since your refer json package) if you have save the response to as a .json file:
import json
with open('response.json', 'r') as handl:
data = json.load(handl)
to_keep = ['id', 'name', 'priority', 'levelStr', 'escalatingChainId',
'escalatingChainName']
new_data = [{k:v for k,v in low_dict.items() if k in to_keep}
for low_dict in data['data']['items']]
escalations = [{v+'Name':k[v]['name']} for k in data['data']['items']
for v in k if type(k[v])==dict]
new_data = [{**new,**escl} for new,escl in zip(new_data,escalations)]
Both produce output:
[{'id': 11,
'name': 'BBC',
'priority': 4,
'levelStr': 'All',
'escalatingChainId': 3,
'escalatingChainName': 'Example123'},
{'id': 21,
'name': 'CNBC',
'priority': 4,
'levelStr': 'All',
'escalatingChainId': 3,
'escalatingChainName': 'Example456'}]

Merge data from list of dict

I think what I want to do is easy but I don't know the correct way to do this.
I have a list as:
[
{
"id": 16,
"condition": true,
"tags": 6,
},
{
"id": 16,
"condition": true,
"tags": 1,
},
{
"id": 16,
"condition": true,
"tags": 4,
},
{
"id": 3,
"condition": false,
"tags": 3,
}
]
And I want to group the element of by list by id and condition, the output would be:
[
{
"id": 16,
"condition": true,
"tags": [6, 1, 4],
},
{
"id": 16,
"condition": false,
"tags": [3],
}
]
I can do this by looping on my list and creating another array but I was wondering about a better way to do this.
for now my code is like this:
def format(self):
list_assigned = the_list_I_want_to_modify
res = []
for x in list_assigned:
exists = [v for v in res if
v['id'] == x['id'] and v['condition'] == x['condition']]
if not exists:
x['tags'] = [x['tags']]
res.append(x)
else:
exists[0]['tags'].append(x['tags'])
return res
Thanks
There might be a prettier solution, but you could solve it by first creating a temporary dictionary with keys being tuples containing all the keys from your original list that are required to group by, and appending the tags in a list - I use the .setdefault(key, type) dictionary function to make a dictionary with default list elements.
Then you can unpack that dictionary into a list again afterwards with a list comprehension.
a = [
{
"id": 16,
"condition": True,
"tags": 6,
},
{
"id": 16,
"condition": True,
"tags": 1,
},
{
"id": 16,
"condition": True,
"tags": 4,
},
{
"verified_by": 3,
"condition": False,
"tags": 3,
}
]
tmp = {}
for elem in a:
groupby_keys = tuple(sorted((k, v) for k, v in elem.items() if k != 'tags'))
tmp.setdefault(groupby_keys, []).append(elem['tags'])
out = [{a[0]: a[1] for a in list(k) + [('tags', v)]} for k, v in tmp.items()]
print(out)
Output:
>>> out
[{'id': 16, 'condition': True, 'tags': [6, 1, 4]}, {'verified_by': 3, 'condition': False, 'tags': [3]}]

how to create a dynamic dictionary with lists in it using JSON python?

I have dictionary formate which contain 4 lists and in the end, I want to convert it into JSON.
modelOutput = {
"projectYears": 1,
"RevSev": [
{
"name": "FixedSavings",
"fixedSavingsCost": []
}, {
"name": "variableSavings",
"variableSavingsCost": []
}, {
"name": "startUpSavings",
"startUpSavingsCost": []
}, {
"name": "shutDownSavings",
"shutDownSavingsCost": []
},
],
}
SO if the projectYear value is 2 then there will be 2 dictionaries with 4 lists(Cost) with 2 random values in it in each dictionary.
expected output:
#if projectYear = 2
modelOutput = {
"projectYears": 1,
"RevSev": [
{
"name": "FixedSavings",
"fixedSavingsCost": [12,22]
}, {
"name": "variableSavings",
"variableSavingsCost": [11,15]
}, {
"name": "startUpSavings",
"startUpSavingsCost": [32,21]
}, {
"name": "shutDownSavings",
"shutDownSavingsCost": [21,33]
},
],
"projectYears": 2,
"RevSev": [
{
"name": "FixedSavings",
"fixedSavingsCost": [32,23]
}, {
"name": "variableSavings",
"variableSavingsCost": [23,12]
}, {
"name": "startUpSavings",
"startUpSavingsCost": [14,32]
}, {
"name": "shutDownSavings",
"shutDownSavingsCost": [14,13]
},
],
Similarly, if projectYears is 3 then there will 3 dictionaries with 4 lists and 3 values in each of them. I was able to create the random values in the lists according to the projectYears but can't able to form separate dictionaries out of it.
My Approach:
projectLife = 3
modelOutput['RevSev'][0]['fixedSavingsCost'] = [random.randrange(1, 50, 1) for i in range(projectLife)]
modelOutput['RevSev'][0]['variableSavingsCost'] = [random.randrange(1, 50, 1) for i in range(projectLife)]
modelOutput['RevSev'][0]['startUpSavingsCost'] = [random.randrange(1, 50, 1) for i in range(projectLife)]
modelOutput['RevSev'][0]['shutDownSavingsCost'] = [random.randrange(1, 50, 1) for i in range(projectLife)]
json.dumps(modelOutput)
Here's a fairly straightforward way of doing that, given modelOutput like the above as input (or even given just the number of years you'd like to have):
years = modelOutput["projectYears"]
randoms = lambda y: np.random.randint(10, 30, y)
res = []
for year in range(1, years+1):
new_year = {
"projectYears": year,
"RevSev": [
{
"name": "FixedSavings",
"fixedSavingsCost": randoms(years)
}, {
"name": "variableSavings",
"variableSavingsCost": randoms(years)
}, {
"name": "startUpSavings",
"startUpSavingsCost": randoms(years)
}, {
"name": "shutDownSavings",
"shutDownSavingsCost": randoms(years)
}
]
}
res.append(new_year)
The result for '2' is:
[{'projectYears': 1,
'RevSev': [{'name': 'FixedSavings', 'fixedSavingsCost': array([24, 22])},
{'name': 'variableSavings', 'variableSavingsCost': array([11, 12])},
{'name': 'startUpSavings', 'startUpSavingsCost': array([27, 22])},
{'name': 'shutDownSavings', 'shutDownSavingsCost': array([25, 17])}]},
{'projectYears': 2,
'RevSev': [{'name': 'FixedSavings', 'fixedSavingsCost': array([15, 19])},
{'name': 'variableSavings', 'variableSavingsCost': array([20, 13])},
{'name': 'startUpSavings', 'startUpSavingsCost': array([26, 22])},
{'name': 'shutDownSavings', 'shutDownSavingsCost': array([24, 25])}]}]

appending onto JSON in python

I have a JSON file that has peoples names in and lists there children.
people.json:
{
"person": [
{
"Id": 0,
"firstName": "Bob",
"lastName": "Bruce",
"children": [
{
"Id": 0,
"Name": "Phil",
},
{
"Id": 1,
"Name": "Dave",
}
]
},
{
"Id": 1,
"firstName": "Fred",
"lastName": "Gone",
"children": [
{
"Id": 0,
"Name": "Harry",
}
]
}
]
}
I want to be able to add a child onto a person. How would I go about doing this. This is my attempt to add a child onto Fred.
people.py
import json
json_data = open("people.json")
data = json.load(json_data)
for d in data['person']:
if d['firstName'] == "Fred":
d['children'] + [{u'Id': 1, u'Name': u'Rich'}]
print d['children']
When it prints out it only prints out the existing data and not what I have tried to add
Your line:
d['children'] + [{u'Id': 1, u'Name': u'Rich'}]
isn't actually adding it in, just calculating it. You can do
d['children'].append({u'Id': 1, u'Name': u'Rich'})
This line:
d['children'] + [{u'Id': 1, u'Name': u'Rich'}]
changes nothing.
d['children'].append({u'Id': 1, u'Name': u'Rich'})

Categories

Resources