converting an unordered nested json into a specific format - python

I have a json like this :
[
{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"more": { "sd": 2, "fg": 5, "ef": 6 },
"s": 6,
"as": 8,
"dfd": [{ "sda": "something", "SX": ["CB"], "jhgjh": "", "das": "" }]
},
{
"a3": 1,
"b": 2,
"c": 3,
"ds": 4,
"more": { "sd": 32, "fg": 5, "3ef": 6 },
"s": 6,
"as": 38,
"dfd": [
{ "sda": "somethinDDDg", "SX": ["CDB"], "jhgjh": "1", "das": "wes" }
]
}
]
I am trying to loop over all levels and convert the json into a specific format. I json can have any number of key value pairs and levels. Key value pairs can be different for each json entry.
I tried using for loop on key value pair and was able to get it converted into the required format on first level of json. I am unable to expand it to any level (where level is not fixed).
Expected output :
'data' : [{
{
'name' : 'a',
'value':1
},
{
'name' : 'b',
'value': 2
},
{
'name' : 'c',
'value': 3
},
{
'name' : 'd',
'value': 4
},
{
'name' : 'more',
'value': {'name' :'sd',
'value': 2},
{'name' : 'fg',
'value' : 5},
{'name':'ef',
'value':6},
{
'name' : 's',
'value': 6
},
{
'name' : 'as',
'value':
},
{
'name' : 'dfd',
'value': [ {"sda": "something",
"SX":["CB"],
"jhgjh": "",
"das": ''
}]
},
{{
'name' : 'a3',
'value':1
},
{
'name' : 'b',
'value': 2
},
{
'name' : 'c',
'value': 3
},
{
'name' : 'ds',
'value': 4
},
{
'name' : 'more',
'value': {'name' :'sd',
'value': 32},
{'name' : 'fg',
'value' : 5},
{'name':'3ef',
'value':6},
{
'name' : 's',
'value': 6
},
{
'name' : 'as',
'value': 38
},
{
'name' : 'dfd',
'value': [ {"sda": "somethinDDDg",
"SX":["CDB"],
"jhgjh": "1",
"das": 'wes'
}]
}}]

Okay, I think I understand now what you want. Using a recursive helper function:
def names_and_values(d):
if type(d) != dict:
return d
return [{"name": key, "value": names_and_values(value)} for key, value in d.items()]
And the json module from the standard library:
import json
data = json.loads(your_json_string)
converted_data = [names_and_values(d) for d in data]
Output:
[[{'name': 'a', 'value': 1},
{'name': 'b', 'value': 2},
{'name': 'c', 'value': 3},
{'name': 'd', 'value': 4},
{'name': 'more',
'value': [{'name': 'sd', 'value': 2},
{'name': 'fg', 'value': 5},
{'name': 'ef', 'value': 6}]},
{'name': 's', 'value': 6},
{'name': 'as', 'value': 8},
{'name': 'dfd',
'value': [{'sda': 'something',
'SX': ['CB'],
'jhgjh': '',
'das': ''}]}],
[{'name': 'a3', 'value': 1},
{'name': 'b', 'value': 2},
{'name': 'c', 'value': 3},
{'name': 'ds', 'value': 4},
{'name': 'more',
'value': [{'name': 'sd', 'value': 32},
{'name': 'fg', 'value': 5},
{'name': '3ef', 'value': 6}]},
{'name': 's', 'value': 6},
{'name': 'as', 'value': 38},
{'name': 'dfd',
'value': [{'sda': 'somethinDDDg',
'SX': ['CDB'],
'jhgjh': '1',
'das': 'wes'}]}]]

Related

How to delete nested element from mongo db based on conditon

{
"_id":62749de1c511aff4354802f0
"filename":"anomaly-detection-using-amazon.pdf"
"tags":[
{'entity': 'Aws', 'count': 21},
{'entity': 'Keras', 'count': 1},
{'entity': 'Amazon Ml', 'count': 1},
{'entity': 'Amazon Cloudwatch', 'count': 1}
]
}
if value of entity string length less than 3 then output is
{
"_id":62749de1c511aff4354802f0
"filename":"anomaly-detection-using-amazon.pdf"
"tags":[
{'entity': 'Keras', 'count': 1},
{'entity': 'Amazon Ml', 'count': 1},
{'entity': 'Amazon Cloudwatch', 'count': 1}
]
}
This my document where i want to delete an entity key from tags array if length of the key value as string is less than 3
Try this one:
db.collection.aggregate([
{
$set: {
tags: {
$filter: {
input: "$tags",
cond: { $gt: [{ $strLenCP: "$$this.entity" }, 3] }
}
}
}
}
])
Mongo Playground

How to filter nested json array on Python

I have a json array on python which I want to filter based on the value of : my_json_array['models']['variants']['condition']['type']
my json array looks like the following :
my_json_array = [
{'id': 1,
'models': [
{'color': {'code': '#626262', 'name': 'Gray'},
'variants': [{'id': 1,
'condition': [{'id': 1,
'type': 'type1',
'value': 14900},
{'id': 2,
'type': 'type2',
'value': 14000}]]
]
}]
I'm looking for a method to remove condition items with type = type2. The output should look like this :
my_json_array = [{
'id': 1,
'models': [
{'color': {'code': '#626262', 'name': 'Gray'},
'variants': [{'id': 1,
'condition': [{'id': 1,
'type': 'type1',
'value': 14900}]]
]
}]
Do you mean this?
my_json_array = [
{
'id': 1,
'models': [
{
'color': {'code': '#626262', 'name': 'Gray'},
'variants': [
{
'id': 1,
'condition': [
{
'id': 1,
'type': 'type1',
'value': 14900
},
{
'id': 2,
'type': 'type2',
'value': 14000
}
]
}
]
}
]
}
]
for mydict in my_json_array:
for model in mydict['models']:
for variant in model['variants']:
for condition in variant['condition']:
if condition['type']=="type2":
variant['condition'].remove(condition)
print(my_json_array) # [{'id': 1, 'models': [{'color': {'code': '#626262', 'name': 'Gray'}, 'variants': [{'id': 1, 'condition': [{'id': 1, 'type': 'type1', 'value': 14900}]}]}]}]

Creating Lists of Dictionaries with N dicts per list

Problem
I am dealing with a response object and I am trying to massage it into something which could be easily consumed by a Typescript frontend.
The object:
r_obj = [
{
'custom_fields': [
{'id': 360018501198, 'value': '5678'},
{'id': 360023508598, 'value': 'Jim'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
},
{
'custom_fields': [
{'id': 360018501198, 'value': '1234'},
{'id': 360023508598, 'value': 'Bob'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
}
]
Desired Structure
[
{
"order_id": '5678',
"name": "Jim",
"date": '2021-09-03'
},
{
"order_id": '1234',
"name": "Bob",
"date": '2021-09-03'
},
]
So id values in the custom_field payload are known and I want to map them to enum representation and with the hope that the output payload contain saner k,v pairs.
The Code
I have only managed to do the mapping of the enum values.
if __name__ == "__main__":
class FieldEnum(enum.IntEnum):
ORDER_ID = 360018501198
DATE = 1900000084913
NAME = 360023508598
r_obj = [
{
'custom_fields': [
{'id': 360018501198, 'value': '5678'},
{'id': 360023508598, 'value': 'Jim'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
},
{
'custom_fields': [
{'id': 360018501198, 'value': '1234'},
{'id': 360023508598, 'value': 'Bob'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
}
]
for row in r_obj:
for field in row['custom_fields']:
if field['id']:
field['id'] = FieldEnum(field['id']).name.lower()
print(field)
Code Output
{'id': 'order_id', 'value': '5678'}
{'id': 'name', 'value': 'Jim'}
{'id': 'date', 'value': '2021-09-03'}
{'id': 'order_id', 'value': '1234'}
{'id': 'name', 'value': 'Bob'}
{'id': 'date', 'value': '2021-09-03'}
I am struggling with how best to group(?) each set of 3 dicts into its own list structure.
EDIT
As per #balderman, I have altered to this:
if __name__ == "__main__":
class FieldEnum(enum.IntEnum):
ORDER_ID = 360018501198
DATE = 1900000084913
NAME = 360023508598
r_obj = [
{
'custom_fields': [
{'id': 360018501198, 'value': '5678'},
{'id': 360023508598, 'value': 'Jim'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
},
{
'custom_fields': [
{'id': 360018501198, 'value': '1234'},
{'id': 360023508598, 'value': 'Bob'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
}
]
out = list()
for entry in r_obj:
out.append({})
for f in entry['custom_fields']:
out[-1][FieldEnum(f['id']).name.lower()] = f['value']
print(out)
Code Output
[
{
'order_id': '5678',
'name': 'Jim',
'date': '2021-09-03'
},
{
'order_id': '1234',
'name': 'Bob',
'date': '2021-09-03'
}
]
Which is the desired output.
I was wondering if there is another way syntactically to achieve the same output?
I would do it with a list comprehension to make it one-liner
code:
import enum
class FieldEnum(enum.IntEnum):
ORDER_ID = 360018501198
DATE = 1900000084913
NAME = 360023508598
r_obj = [
{
'custom_fields': [
{'id': 360018501198, 'value': '5678'},
{'id': 360023508598, 'value': 'Jim'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
},
{
'custom_fields': [
{'id': 360018501198, 'value': '1234'},
{'id': 360023508598, 'value': 'Bob'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
}
]
print([{FieldEnum(f['id']).name.lower():f['value'] for f in entry['custom_fields'] } for entry in r_obj])
result:
[
{"order_id": "5678", "name": "Jim", "date": "2021-09-03"},
{"order_id": "1234", "name": "Bob", "date": "2021-09-03"},
]
try the below
lookup = {360018501198: 'order_id', 360023508598: 'name', 1900000084913: 'date'}
data = [{
'custom_fields': [
{'id': 360018501198, 'value': '5678'},
{'id': 360023508598, 'value': 'Jim'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
},
{
'custom_fields': [
{'id': 360018501198, 'value': '1234'},
{'id': 360023508598, 'value': 'Bob'},
{'id': 1900000084913, 'value': '2021-09-03'}
]
}
]
out = list()
for entry in data:
out.append({})
for f in entry['custom_fields']:
out[-1][lookup[f['id']]] = f['value']
print(out)
output
[{'order_id': '5678', 'name': 'Jim', 'date': '2021-09-03'}, {'order_id': '1234', 'name': 'Bob', 'date': '2021-09-03'}]

Group python list of dictionaries by values

Given I have a list of dictionaries I want to create new list of lists grouping the dictionaries by the values of "price":
dicts = [
{ "name": "item1", "price": 10 },
{ "name": "item2", "price": 5 },
{ "name": "item3", "price": 10 },
{ "name": "item4", "price": 12 },
{ "name": "item5", "price": 12 },
{ "name": "item6", "price": 5 }
]
Should create:
grouped_dicts = [
[{ "name": "item1", "price": 10 },
{ "name": "item3", "price": 10 }],
[{ "name": "item2", "price": 5 },
{ "name": "item6", "price": 5 }],
[{ "name": "item4", "price": 12 },
{ "name": "item5", "price": 12 }]
]
Is there a nice way of doing this?
Thanks
As an alternative to the answer above, here is how you do it without an additional import:
d = {}
for item in dicts:
d.setdefault(item['price'], []).append(item)
list(d.values())
Out:
[[{'name': 'item1', 'price': 10}, {'name': 'item3', 'price': 10}],
[{'name': 'item2', 'price': 5}, {'name': 'item6', 'price': 5}],
[{'name': 'item4', 'price': 12}, {'name': 'item5', 'price': 12}]]
You could use deaultdict
from collections import defaultdict
d=defaultdict(list)
for item in dicts:
d[list(item.values())[-1]].append(item)
Output:
defaultdict(list,
{10: [{'name': 'item1', 'price': 10},
{'name': 'item3', 'price': 10}],
5: [{'name': 'item2', 'price': 5}, {'name': 'item6', 'price': 5}],
12: [{'name': 'item4', 'price': 12},
{'name': 'item5', 'price': 12}]})
If you just need the list then just extract the values of defaultdict
list(d.values())
Output:
[[{'name': 'item1', 'price': 10}, {'name': 'item3', 'price': 10}],
[{'name': 'item2', 'price': 5}, {'name': 'item6', 'price': 5}],
[{'name': 'item4', 'price': 12}, {'name': 'item5', 'price': 12}]]

While creating a Dictionary: TypeError: unhashable type: 'dict'

I'm trying to script a simple Character Generator that I can use for Pen and Paper RPG's. I was thinking about storing all my information in a nested dictionary and saving it into a JSON file.
However, while creating the following dictionary, I receive as error:
nhashable type: 'dict', focussing on {'cha': 1}}}
core_phb = {
'races': {
'Human': {
{'abilities': 'None'},
{'alignment': 'Neutral'},
{'size': 'Medium'},
{'speed': 6},
{'languages': 'Common'},
{'ability_modifiers': {
{'str': 1},
{'dex': 1},
{'con': 1},
{'int': 1},
{'wis': 1},
{'cha': 1}}}
},
'Dwarf': {
{'abilities': [
'ability1',
'ability2'
]},
{'alignment': 'Lawful Good'},
{'size': 'Medium'},
{'speed': 5},
{'languages': [
'Common',
'Dwarven'
]},
{'ability_modifiers': [
{'con': 2},
{'wis': 1}
]}
},
'Elf': {
{'abilities': [
'ability1',
'ability2'
]},
{'alignment': 'Chaotic Good'},
{'size': 'Medium'},
{'speed': 6},
{'languages': [
'Common',
'Elven'
]},
{'ability_modifiers': [
{'dex': 2},
{'int': 1}
]}
}
},
'classes': {
{'Fighter': {}},
{'Ranger': {}},
{'Wizard': {}}
},
'ability_scores': [
{'Str': 'str'},
{'Dex': 'dex'},
{'Con': 'con'},
{'Int': 'int'},
{'Wis': 'wis'},
{'Cha': 'cha'}]
}
I am simply trying to create the dictionary, not calling any keys from it.
As I understand from TypeError: unhashable type: 'dict' , I can use frozenset() to get keys.
Is there a better way to do what I am trying to do?
You seem to be making dictionaries {...} incorrectly for Python.
Lists look like this:
[ {'a': 1}, {'b': 1}, {'c': 1} ]
Dictionaries look like this:
{ 'a': 1, 'b': 2, 'c': 3 }
If I'm guessing the behavior you want correctly, then you probably wanted something like this:
human = {
'abilities': 'None',
'alignment': 'Neutral',
'size': 'Medium',
'speed': 6,
'languages': 'Common',
'ability_modifiers': {
'str': 1,
'dex': 1,
'con': 1,
'int': 1,
'wis': 1,
'cha': 1
}
}
The problem is not with the dicts, but with the sets. The elements of a set must be hashable. In
core_phb = {
'races': {
'Human': {
{'abilities': 'None'},
{'alignment': 'Neutral'},
{'size': 'Medium'},
{'speed': 6},
{'languages': 'Common'},
{'ability_modifiers': {
{'str': 1},
{'dex': 1},
{'con': 1},
{'int': 1},
{'wis': 1},
{'cha': 1}}}
},
'Dwarf': {
{'abilities': [
'ability1',
'ability2'
]},
{'alignment': 'Lawful Good'},
{'size': 'Medium'},
{'speed': 5},
{'languages': [
'Common',
'Dwarven'
]},
{'ability_modifiers': [
{'con': 2},
{'wis': 1}
]}
},
'Elf': {
{'abilities': [
'ability1',
'ability2'
]},
{'alignment': 'Chaotic Good'},
{'size': 'Medium'},
{'speed': 6},
{'languages': [
'Common',
'Elven'
]},
{'ability_modifiers': [
{'dex': 2},
{'int': 1}
]}
}
},
'classes': {
{'Fighter': {}},
{'Ranger': {}},
{'Wizard': {}}
},
'ability_scores': [
{'Str': 'str'},
{'Dex': 'dex'},
{'Con': 'con'},
{'Int': 'int'},
{'Wis': 'wis'},
{'Cha': 'cha'}]
}
the key is fine, but the value is an illegal set, because its elements are dicts. You could make frozensets from the sets and you'd be OK.
{frozenset({1})}
{frozenset({1})}
{{1}}
Traceback (most recent call last):
Python Shell, prompt 7, line 1
builtins.TypeError: unhashable type: 'set'
I think this :
'Human': {
{'abilities': 'None'},
{'alignment': 'Neutral'},
{'size': 'Medium'},
{'speed': 6},
{'languages': 'Common'},
{'ability_modifiers': {
{'str': 1},
{'dex': 1},
{'con': 1},
{'int': 1},
{'wis': 1},
{'cha': 1}}}
},
should be a list. Otherwise, each of the comma-separated elements is a mutable element which you are trying to store in a set. You are already doing it right with the very last entry:
'ability_scores': [
{'Str': 'str'},
{'Dex': 'dex'},
{'Con': 'con'},
{'Int': 'int'},
{'Wis': 'wis'},
{'Cha': 'cha'}]
so why not all the others?

Categories

Resources