I am trying to convert a dictionary using json.dumps()
def create_custom(json_input):
custom = dict()
custom['list'] = dict()
custom['list']['Elements'] = json_input['nodes']
custom['list']['links'] = json_input['links']
return custom
JsonData = create_custom(json_graph.node_link_data(G))
for i, j in enumerate(Elements):
JsonData['list']['Elements'][i]['Shape'] = j['Shape']
The above code is not complete but the final output I am getting is a dictionary
Output
{'list': {'Elements': [{'text': 'Task 1', 'Shape': 'Decision', 'id': 0},
{'text': 'Task 2', 'Shape': 'Decision', 'id': 1},
{'text': 'Task 3', 'Shape': 'Decision', 'id': 2},
{'text': 'Task 4', 'Shape': 'Decision', 'id': 3},
{'text': 'Task 5', 'Shape': 'Rectangle', 'id': 4},
{'text': 'Task 6', 'Shape': 'Decision', 'id': 5}],
'links': [{'source': 0, 'target': 1, 'key': 0},
{'source': 0, 'target': 4, 'key': 0},
{'source': 1, 'target': 2, 'key': 0},
{'source': 1, 'target': 3, 'key': 0},
{'source': 2, 'target': 1, 'key': 0},
{'source': 2, 'target': 4, 'key': 0},
{'source': 3, 'target': 1, 'key': 0},
{'source': 3, 'target': 4, 'key': 0},
{'source': 4, 'target': 5, 'key': 0},
{'source': 5, 'target': 4, 'key': 0},
{'source': 5, 'target': 1, 'key': 0}]}}
When I am converting the above output to JSON object
json.dumps(JsonData)
I am getting an error:
~\AppData\Local\Continuum\anaconda3\lib\json\encoder.py in default(self, o)
177
178 """
--> 179 raise TypeError(f'Object of type {o.__class__.__name__} '
180 f'is not JSON serializable')
181
TypeError: Object of type int64 is not JSON serializable
I went across many answers but they are saying about numpy array etc.
Where I am going wrong
I could not recreate the error, but json.dumps worked fine for me. Please refer to the screenshot below:
Code I tried:
import json
JsonData={'list': {'Elements': [{'text': 'Task 1', 'Shape': 'Decision', 'id': 0},
{'text': 'Task 2', 'Shape': 'Decision', 'id': 1},
{'text': 'Task 3', 'Shape': 'Decision', 'id': 2},
{'text': 'Task 4', 'Shape': 'Decision', 'id': 3},
{'text': 'Task 5', 'Shape': 'Rectangle', 'id': 4},
{'text': 'Task 6', 'Shape': 'Decision', 'id': 5}],
'links': [{'source': 0, 'target': 1, 'key': 0},
{'source': 0, 'target': 4, 'key': 0},
{'source': 1, 'target': 2, 'key': 0},
{'source': 1, 'target': 3, 'key': 0},
{'source': 2, 'target': 1, 'key': 0},
{'source': 2, 'target': 4, 'key': 0},
{'source': 3, 'target': 1, 'key': 0},
{'source': 3, 'target': 4, 'key': 0},
{'source': 4, 'target': 5, 'key': 0},
{'source': 5, 'target': 4, 'key': 0},
{'source': 5, 'target': 1, 'key': 0}]}}
print(type(JsonData))
print(json.dumps(JsonData))
print(type(json.dumps(JsonData)))
Related
This question already has answers here:
Avoiding nested for loops
(3 answers)
Closed 3 months ago.
I want to combine my id list with my status list and I used list comprehension to do it:
# id
id_list = [
1, # UAE1S
2, # UAE2S
3, # UAE3S
]
# status
status_list = [
'okay',
'not okay',
'unknown',
]
result = [
{
'id':id,
'status':status,
}
for id in id_list
for status in status_list
]
print(result)
[{'id': 1, 'status': 'okay'}, {'id': 1, 'status': 'not okay'}, {'id': 1, 'status': 'unknown'}, {'id': 2, 'status': 'okay'}, {'id': 2, 'status': 'not okay'}, {'id': 2, 'status': 'unknown'}, {'id': 3, 'status': 'okay'}, {'id': 3, 'status': 'not okay'}, {'id': 3, 'status': 'unknown'}]
It's outputting the correct list but is there a way to remove the nested for loop?
itertools.product gives the cartesian product,
import itertools
id_list = [1, 2, 3]
status_list = ['okay','not okay','unknown',]
[{'id': item[0], 'status': item[1]} for item in itertools.product(id_list, status_list)]
[{'status': 'okay', 'id': 1}, {'status': 'not okay', 'id': 1}, {'status': 'unknown', 'id': 1}, {'status': 'okay', 'id': 2}, {'status': 'not okay', 'id': 2}, {'status': 'unknown', 'id': 2}, {'status': 'okay', 'id': 3}, {'status': 'not okay', 'id': 3}, {'status': 'unknown', 'id': 3}]
I found some elegant code that builds a list by iterating through each element of another JSON list:
results = [
(
t["vintage"]["wine"]["winery"]["name"],
t["vintage"]["year"],
t["vintage"]["wine"]["id"],
f'{t["vintage"]["wine"]["name"]} {t["vintage"]["year"]}',
t["vintage"]["wine"]["statistics"]["ratings_average"],
t["vintage"]["wine"]["statistics"]["ratings_count"],
t["price"]["amount"],
t["vintage"]["wine"]["region"]["name"],
t["vintage"]["wine"]["style"]["name"], #<--------------issue here
)
for t in r.json()["explore_vintage"]["matches"]
]
The problem is that sometimes the JSON doesn't have a "name" element because the "style" is null (or None in JSON world). See the second-last line below for the JSON sample.
Is there a simple way to handle this error?
Error:
matches[23]["vintage"]["wine"]["style"]["name"]
Traceback (most recent call last):
File "<ipython-input-94-59447d0d4859>", line 1, in <module>
matches[23]["vintage"]["wine"]["style"]["name"]
TypeError: 'NoneType' object is not subscriptable
Perhaps something like:
iferror(t["vintage"]["wine"]["style"]["name"], "DoesNotExist")
JSON:
{'id': 4026076,
'name': 'Shiraz - Petit Verdot',
'seo_name': 'shiraz-petit-verdot',
'type_id': 1,
'vintage_type': 0,
'is_natural': False,
'region': {'id': 685,
'name': 'South Eastern Australia',
'name_en': '',
'seo_name': 'south-eastern',
'country': {'code': 'au',
'name': 'Australia',
'native_name': 'Australia',
'seo_name': 'australia',
'sponsored': False,
'currency': {'code': 'AUD',
'name': 'Australian Dollars',
'prefix': '$',
'suffix': None},
'regions_count': 120,
'users_count': 867353,
'wines_count': 108099,
'wineries_count': 13375,
'most_used_grapes': [{'id': 1,
'name': 'Shiraz/Syrah',
'seo_name': 'shiraz-syrah',
'has_detailed_info': True,
'wines_count': 536370},
{'id': 2,
'name': 'Cabernet Sauvignon',
'seo_name': 'cabernet-sauvignon',
'has_detailed_info': True,
'wines_count': 780931},
{'id': 5,
'name': 'Chardonnay',
'seo_name': 'chardonnay',
'has_detailed_info': True,
'wines_count': 586874}],
'background_video': None},
'class': {'typecast_map': {'background_image': {}, 'class': {}}},
'background_image': {'location': '//images.vivino.com/regions/backgrounds/0iT8wuQXRWaAmEGpPjZckg.jpg',
'variations': {'large': '//thumbs.vivino.com/region_backgrounds/0iT8wuQXRWaAmEGpPjZckg_1280x760.jpg',
'medium': '//thumbs.vivino.com/region_backgrounds/0iT8wuQXRWaAmEGpPjZckg_600x356.jpg'}}},
'winery': {'id': 74363,
'name': 'Barramundi',
'seo_name': 'barramundi',
'status': 0,
'background_image': None},
'taste': {'structure': None,
'flavor': [{'group': 'black_fruit', 'stats': {'count': 16, 'score': 2987}},
{'group': 'oak', 'stats': {'count': 11, 'score': 1329}},
{'group': 'red_fruit', 'stats': {'count': 10, 'score': 1413}},
{'group': 'spices', 'stats': {'count': 6, 'score': 430}},
{'group': 'non_oak', 'stats': {'count': 5, 'score': 126}},
{'group': 'floral', 'stats': {'count': 3, 'score': 300}},
{'group': 'earth', 'stats': {'count': 3, 'score': 249}},
{'group': 'microbio', 'stats': {'count': 2, 'score': 66}},
{'group': 'vegetal', 'stats': {'count': 1, 'score': 100}},
{'group': 'dried_fruit', 'stats': {'count': 1, 'score': 100}}]},
'statistics': {'status': 'Normal',
'ratings_count': 1002,
'ratings_average': 3.5,
'labels_count': 11180,
'vintages_count': 25},
'style': None,
'has_valid_ratings': True}
In the following example, I would like to sort the animals by the alphabetical order of their category, which is stored in an order dictionnary.
category = [{'uid': 0, 'name': 'mammals'},
{'uid': 1, 'name': 'birds'},
{'uid': 2, 'name': 'fish'},
{'uid': 3, 'name': 'reptiles'},
{'uid': 4, 'name': 'invertebrates'},
{'uid': 5, 'name': 'amphibians'}]
animals = [{'name': 'horse', 'category': 0},
{'name': 'whale', 'category': 2},
{'name': 'mollusk', 'category': 4},
{'name': 'tuna ', 'category': 2},
{'name': 'worms', 'category': 4},
{'name': 'frog', 'category': 5},
{'name': 'dog', 'category': 0},
{'name': 'salamander', 'category': 5},
{'name': 'horse', 'category': 0},
{'name': 'octopus', 'category': 4},
{'name': 'alligator', 'category': 3},
{'name': 'monkey', 'category': 0},
{'name': 'kangaroos', 'category': 0},
{'name': 'salmon', 'category': 2}]
sorted_animals = sorted(animals, key=lambda k: (k['category'])
How could I achieve this?
Thanks.
You are now sorting on the category id. All you need to do is map that id to a lookup for a given category name.
Create a dictionary for the categories first so you can directly map the numeric id to the associated name from the category list, then use that mapping when sorting:
catuid_to_name = {c['uid']: c['name'] for c in category}
sorted_animals = sorted(animals, key=lambda k: catuid_to_name[k['category']])
Demo:
>>> from pprint import pprint
>>> category = [{'uid': 0, 'name': 'mammals'},
... {'uid': 1, 'name': 'birds'},
... {'uid': 2, 'name': 'fish'},
... {'uid': 3, 'name': 'reptiles'},
... {'uid': 4, 'name': 'invertebrates'},
... {'uid': 5, 'name': 'amphibians'}]
>>> animals = [{'name': 'horse', 'category': 0},
... {'name': 'whale', 'category': 2},
... {'name': 'mollusk', 'category': 4},
... {'name': 'tuna ', 'category': 2},
... {'name': 'worms', 'category': 4},
... {'name': 'frog', 'category': 5},
... {'name': 'dog', 'category': 0},
... {'name': 'salamander', 'category': 5},
... {'name': 'horse', 'category': 0},
... {'name': 'octopus', 'category': 4},
... {'name': 'alligator', 'category': 3},
... {'name': 'monkey', 'category': 0},
... {'name': 'kangaroos', 'category': 0},
... {'name': 'salmon', 'category': 2}]
>>> catuid_to_name = {c['uid']: c['name'] for c in category}
>>> pprint(catuid_to_name)
{0: 'mammals',
1: 'birds',
2: 'fish',
3: 'reptiles',
4: 'invertebrates',
5: 'amphibians'}
>>> sorted_animals = sorted(animals, key=lambda k: catuid_to_name[k['category']])
>>> pprint(sorted_animals)
[{'category': 5, 'name': 'frog'},
{'category': 5, 'name': 'salamander'},
{'category': 2, 'name': 'whale'},
{'category': 2, 'name': 'tuna '},
{'category': 2, 'name': 'salmon'},
{'category': 4, 'name': 'mollusk'},
{'category': 4, 'name': 'worms'},
{'category': 4, 'name': 'octopus'},
{'category': 0, 'name': 'horse'},
{'category': 0, 'name': 'dog'},
{'category': 0, 'name': 'horse'},
{'category': 0, 'name': 'monkey'},
{'category': 0, 'name': 'kangaroos'},
{'category': 3, 'name': 'alligator'}]
Note that within each category, the dictionaries have been left in relative input order. You could return a tuple of values from the sorting key to further apply a sorting order within each category, e.g.:
sorted_animals = sorted(
animals,
key=lambda k: (catuid_to_name[k['category']], k['name'])
)
would sort by animal name within each category, producing:
>>> pprint(sorted(animals, key=lambda k: (catuid_to_name[k['category']], k['name'])))
[{'category': 5, 'name': 'frog'},
{'category': 5, 'name': 'salamander'},
{'category': 2, 'name': 'salmon'},
{'category': 2, 'name': 'tuna '},
{'category': 2, 'name': 'whale'},
{'category': 4, 'name': 'mollusk'},
{'category': 4, 'name': 'octopus'},
{'category': 4, 'name': 'worms'},
{'category': 0, 'name': 'dog'},
{'category': 0, 'name': 'horse'},
{'category': 0, 'name': 'horse'},
{'category': 0, 'name': 'kangaroos'},
{'category': 0, 'name': 'monkey'},
{'category': 3, 'name': 'alligator'}]
imo your category structure is far too complicated - at least as long as the uid is nothing but the index, you could simply use a list for that:
category = [c['name'] for c in category]
# ['mammals', 'birds', 'fish', 'reptiles', 'invertebrates', 'amphibians']
sorted_animals = sorted(animals, key=lambda k: category[k['category']])
#[{'name': 'frog', 'category': 5}, {'name': 'salamander', 'category': 5}, {'name': 'whale', 'category': 2}, {'name': 'tuna ', 'category': 2}, {'name': 'salmon', 'category': 2}, {'name': 'mollusk', 'category': 4}, {'name': 'worms', 'category': 4}, {'name': 'octopus', 'category': 4}, {'name': 'horse', 'category': 0}, {'name': 'dog', 'category': 0}, {'name': 'horse', 'category': 0}, {'name': 'monkey', 'category': 0}, {'name': 'kangaroos', 'category': 0}, {'name': 'alligator', 'category': 3}]
I have seen Python: remove dictionary from list and Splitting a list of dictionaries into several lists of dictionaries - but this question is slightly different.
Consider this working example (same in Python 2 or 3):
#!/usr/bin/env python
from __future__ import print_function
origarr = [
{ 'name': 'test01', 'type': 0, 'value': 42 },
{ 'name': 'test02', 'type': 0, 'value': 142 },
{ 'name': 'test03', 'type': 2, 'value': 242 },
{ 'name': 'test04', 'type': 2, 'value': 342 },
{ 'name': 'test05', 'type': 3, 'value': 42 },
]
print("origarr: {}".format(origarr))
lastdictelem = origarr.pop()
print("\nlastdictelem: {}".format(lastdictelem))
print("after pop, origarr: {}".format(origarr))
namestofilter = [ 'test01', 'test02' ]
newarr = []
for iname in namestofilter:
# find the object having the name iname
foundidx = -1
for ix, idict in enumerate(origarr):
if idict.get('name') == iname:
foundidx = ix
break
if foundidx > -1:
# remove dict object via pop at index, save removed object
remdict = origarr.pop(foundidx)
# add removed object to newarr:
newarr.append(remdict)
print("\nafter namestofilter:")
print("newarr: {}".format(newarr))
print("origarr: {}".format(origarr))
Basically, mylist.pop() removes the last element from mylist as an object (here a dict), and returns it - then I can trivially insert it in a new array/list; this is illustrated by the first printout of this script:
$ python2 test.py
origarr: [{'name': 'test01', 'type': 0, 'value': 42}, {'name': 'test02', 'type': 0, 'value': 142}, {'name': 'test03', 'type': 2, 'value': 242}, {'name': 'test04', 'type': 2, 'value': 342}, {'name': 'test05', 'type': 3, 'value': 42}]
lastdictelem: {'name': 'test05', 'type': 3, 'value': 42}
after pop, origarr: [{'name': 'test01', 'type': 0, 'value': 42}, {'name': 'test02', 'type': 0, 'value': 142}, {'name': 'test03', 'type': 2, 'value': 242}, {'name': 'test04', 'type': 2, 'value': 342}]
Now, what I would like to do, is define an array with values for the name key in a dict (say, namestofilter = [ 'test01', 'test02' ]), and have those dicts removed from the orriginal array/list, and put into a new array/list (as .pop() would do with a single element and an object reference).
Since pop removes the item at a specific index and returns it, the above code does exactly that - and works:
...
after namestofilter:
newarr: [{'name': 'test01', 'type': 0, 'value': 42}, {'name': 'test02', 'type': 0, 'value': 142}]
origarr: [{'name': 'test03', 'type': 2, 'value': 242}, {'name': 'test04', 'type': 2, 'value': 342}]
... but I was wondering - is there a more compact way of doing that, other than "manually" for-looping through the two arrays, and calling .pop()/.append() individually (as done in the example)?
I'm not sure is there a way to it compact - probaly not.
But you can simpify code a little bit and also don't spend O(n) for each .pop:
origarr = [
{ 'name': 'test01', 'type': 0, 'value': 42 },
{ 'name': 'test02', 'type': 0, 'value': 142 },
{ 'name': 'test03', 'type': 2, 'value': 242 },
{ 'name': 'test04', 'type': 2, 'value': 342 },
{ 'name': 'test05', 'type': 3, 'value': 42 },
]
namestofilter = set([ 'test01', 'test02' ]). # could be a list as in question
print("origarr: {}".format(origarr))
lastdictelem = origarr.pop()
print("\nlastdictelem: {}".format(lastdictelem))
print("after pop, origarr: {}".format(origarr))
shift = 0
newarr = []
for ix, idict in enumerate(origarr):
if idict['name'] in namestofilter:
shift += 1
newarr.append(idict)
continue
origarr[ix-shift] = origarr[ix]
origarr = origarr[:-shift] # perhaps it is a slicing O(n) copy overhead
print("\nafter namestofilter:")
print("newarr: {}".format(newarr))
print("origarr: {}".format(origarr))
Output:
origarr: [{'name': 'test01', 'type': 0, 'value': 42}, {'name': 'test02', 'type': 0, 'value': 142}, {'name': 'test03', 'type': 2, 'value': 242}, {'name': 'test04', 'type': 2, 'value': 342}, {'name': 'test05', 'type': 3, 'value': 42}]
lastdictelem: {'name': 'test05', 'type': 3, 'value': 42}
after pop, origarr: [{'name': 'test01', 'type': 0, 'value': 42}, {'name': 'test02', 'type': 0, 'value': 142}, {'name': 'test03', 'type': 2, 'value': 242}, {'name': 'test04', 'type': 2, 'value': 342}]
after namestofilter:
newarr: [{'name': 'test01', 'type': 0, 'value': 42}, {'name': 'test02', 'type': 0, 'value': 142}]
origarr: [{'name': 'test03', 'type': 2, 'value': 242}, {'name': 'test04', 'type': 2, 'value': 342}]
In Python, I am trying to turn a list of separate JSON data:
[[{'id': 1, 'name': 'pencil', 'description': '2b or not 2b, that is the question'}], [{'id': 2, 'name': 'oil pastel', 'description': None}], [{'id': 3, 'name': 'gouache', 'description': None}], [{'id': 4, 'name': 'paper', 'description': None}]]
into one piece of JSON data:
{'id': 1, 'name': 'pencil', 'description': '2b or not 2b, that is the question'}, {'id': 2, 'name': 'oil pastel', 'description': None}, {'id': 3, 'name': 'gouache', 'description': None}, {'id': 4, 'name': 'paper', 'description': None}, {'id': 5, 'name': 'coloured pencil', 'description': None}
Been struggling with it for a few hours. Does anyone have any ideas?
Use simple list-comprehension
[y for x in list_of_lists for y in x]
Output:
[{'description': '2b or not 2b, that is the question', 'id': 1, 'name': 'pencil'}, {'description': None, 'id': 2, 'name': 'oil pastel'}, {'description': None, 'id': 3, 'name': 'gouache'}, {'description': None, 'id': 4, 'name': 'paper'}]
Use itertools.chain
>>> list(itertools.chain.from_iterable(j))
Or a list comprehension
>>> [x[0] for x in j] # Assuming there is only one item in each list
Both outputs
[{'id': 1,
'name': 'pencil',
'description': '2b or not 2b, that is the question'},
{'id': 2, 'name': 'oil pastel', 'description': None},
{'id': 3, 'name': 'gouache', 'description': None},
{'id': 4, 'name': 'paper', 'description': None}]
Using functools with operator
j = [[{'id': 1, 'name': 'pencil', 'description': '2b or not 2b, that is the question'}], [{'id': 2, 'name': 'oil pastel', 'description': None}], [{'id': 3, 'name': 'gouache', 'description': None}], [{'id': 4, 'name': 'paper', 'description': None}]]
import functools
import operator
functools.reduce(operator.iadd,j,[])
Output:
[{'id': 1,
'name': 'pencil',
'description': '2b or not 2b, that is the question'},
{'id': 2, 'name': 'oil pastel', 'description': None},
{'id': 3, 'name': 'gouache', 'description': None},
{'id': 4, 'name': 'paper', 'description': None}]