Modify nested value in a dictionary - python

Consider this dictionary shown below:
"Title": {
"Label-1": {
"sublabel-1": {
"item1": {},
"item2": {}
},
"sublabel-2": {
"item3": {},
"item4": {},
"item5": {}
}
}
"Label-2": {
"sublabel-1": {
"item6": {},
"item7": {},
"item8": {},
}
}
}
Here is a dictionary to modify some key-value pairs as shown below.
values_to_add={item1:a,item2:b}
The goal is to add values a and b to the respective keys in the dictionary.
For reference, I read the following posts:
1.First Reference:
(The difference is that I just have the key-value pair to modify and not the detailed trail upto the key-value pair as given in the update variable.)
2.Second Reference:
(Unfortunately, no follow up on the question.)
Some additional points:
Level and depth of dictionary may vary. The main focus would be to add values to the innermost keys for any sublabel most of the times.(in this case item1 and item2)
Using python 2 to manipulate the dictionary.
I am currently trying to create a program to work it out. Hopefully looking to get some insights on different approaches to the problem and learn something new.

It looks like your data structure reflects the way you want to output the data, and that is complicating the update process.
Postpone the construction of your nested dictionary. Instead, set up flat a dictionary with only the leaf keys, and the superordinate keys as data:
{
"item1": {'path': ("Title","Label-1","sublabel-1"), "values":{} },
"item2": {'path': ("Title","Label-1","sublabel-1"), "values":{} },
"item3": {'path': ("Title","Label-1","sublabel-2"), "values":{} },
"item4": {'path': ("Title","Label-1","sublabel-2"), "values":{} },
"item5": {'path': ("Title","Label-1","sublabel-2"), "values":{} },
"item6": {'path': ("Title","Label-2","sublabel-1"), "values":{} },
"item7": {'path': ("Title","Label-2","sublabel-1"), "values":{} },
"item8": {'path': ("Title","Label-2","sublabel-1"), "values":{} },
}
When it is complete you can iterate through it and construct the nested structure you want. This also allows you to easily accommodate key paths of varying lengths, which would otherwise make for a very complex access method.
This does of course assume your leaf keys are unique. That was also implicit in your question. It does strike me as an unlikely assumption in practice, though.

Related

Fetch a list from a dictionary based on a nested value?

Lets say I have a dictionary:
episode = {
"translations": [{
"language": {
"code": "de"
},
"title": "German"
}, {
"language": {
"code": "en"
},
"title": "English"
}, {
"language": {
"code": "fr"
},
"title": "French"
}]
};
I would like to get specifically the list that matches a specific language code. I could walk through the entire dictionary using the following code:
for translation in episode['translations']:
if translation['language']['code'] == 'fr':
language = translation;
break;
But that seems a bit excessive, and a waste of resources. Is there a better way of doing this, without having to walk through the entire array?
If the data is stored in a list, then the only way to extract queries based on a condition is to iterate over the entries. In the snippet you provide, the implicit assumption of using break is that there is a unique entry of interest (or perhaps the first match is of interest).
For more optimal queries of this data, it should be transformed to a different structure. For example, it's possible to convert it to a pandas dataframe or convert the data to a dictionary where keys are translation['language']['code'] (so look-ups become O(1)).
Short of modifying how you structured your data*, I don't see a way that doesn't involve traversing the whole dictionary. That being said, there are a few more elegant ways to do it, although elegance is highly subjective:
filter(lambda x: 'fr' in x['language'].values(), episode['translations'])
would give you an iterable that contains all the the entries in your dictionary that have the required language code. Calling next on it would give you the first one, for instance.
Edit:
* what SultanOrazbayev proposed in their answer is one such way to modify your data structure.
A list comprehension is neater although not really different from the original code except that it allows for more than one dictionary entry having a particular code. For example:
episode = {
"translations": [{
"language": {
"code": "de"
},
"title": "German"
}, {
"language": {
"code": "en"
},
"title": "English"
}, {
"language": {
"code": "fr"
},
"title": "French"
}]
}
list_ = [d for d in episode['translations'] if d['language']['code'] == 'en']
print(list_)
Output:
[{'language': {'code': 'en'}, 'title': 'English'}]

How can I mitigate the error in Python Dictionary?

How do I access to visibilities?
I am trying like this: dev1['data']['results :visibilites ']
dev1 = {
"status": "OK",
"data": {
"results": [
{
"tradeRelCode": "ZT55",
"customerCode": "ZC0",
"customerName": "XYZ",
"tier": "null1",
"visibilites": [
{
"code": "ZS0004207",
"name": "Aabc Systems Co.,Ltd",
"siteVisibilityMap": {
},
"customerRef": "null1"
}
]
}
],
"pageNumber": 3,
"limit": 1,
"total": 186
}
}
You can use dev1['data']['results'][0]['visibilites'].
It will contain a list of one dictionary.
To access this dictionary directly, use dev1['data']['results'][0]['visibilites'][0]
dev['data'] represents a dictionary that has for key results.
You can access the item associated to results key (a list) using (dev1['data'])['results'].
To access the only member of this list, you use ((dev1['data'])['results'])[0].
This gives you a dictionary that has tradeRelCode, customerCode, customerName, tier and visibilites keys.
To access the item associated to visibilites key (a list), you have tu use (((dev1['data'])['results'])[0])['visibilites'].
To finally access the only dictionary contained in this list, you have tu use ((((dev1['data'])['results'])[0])['visibilites'])[0].
Parenthesis are here to show that python dig into each dictionary or list in order from left to right (python does not mind the parenthesis in the code, you can keep them if it is clearer for you.)
In your data structure use path
dev1['data']['results'][0]['visibilites']
Try this
dev1['data']['results'][0]['visibilites']
Reason:
This is a list -> dev1['data']['results']
So, access this -> dev1['data']['results'][0]
and then you obtain this ->
{'tradeRelCode': 'ZT55',
'customerCode': 'ZC0',
'customerName': 'XYZ',
'tier': 'null1',
'visibilites': [{'code': 'ZS0004207',
'name': 'Aabc Systems Co.,Ltd',
'siteVisibilityMap': {},
'customerRef': 'null1'}]}
and then you can have -> dev1['data']['results'][0]['visibilites']
which results in ->
[{'code': 'ZS0004207',
'name': 'Aabc Systems Co.,Ltd',
'siteVisibilityMap': {},
'customerRef': 'null1'}]
which is a list and you can index the first element which is another dictionary

How to populate optional fields in a dictionary comprehension?

I'm working on some code that processes a json database with very detailed information into a simpler format. It copies some of the fields and reserializes others into a new json file.
I'm currently using a dictionary comprehension like this MVCE:
converted_data = {
raw_item['name']: {
'state': raw_item['field_a'],
'variations': [variant for variant in raw_item['field_b']['variations']]
} for raw_item in json.loads(my_file.read())
}
An example file (not the actual data being used) is this:
[
{
"name": "Object A",
"field_a": "foo",
"field_b": {
"bar": "baz",
"variants": [
"foo",
"bar",
"baz"
]
}
},
{
"name": "Object B",
"field_a": "foo",
"field_b": {
"bar": "baz",
}
}
]
The challenge is that not all items contain variations. I see two potential solutions:
Use an if statement to conditionally apply the variations field into the dictionary.
Include an empty variations field for all items and fill it if the raw item contains variations.
I'll probably settle on the 2nd solution. However, is there a way to conditionally include a particular field within a dictionary comprehension?
Edit: In other words, is approach 1 possible inside a dictionary comprehension?
An example of the desired output (using a dictionary comprehension) would be as follows:
{
"Object A": {
"state": "foo",
"variants": ["foo", "bar", "baz"]
},
"Object B": {
"state": "foo"
}
}
I've found some other questions that change the entries conditionally or filter the entries, but these don't unconditionally create an item where a particular field (in the item) is conditionally absent.
I'm not sure you realise you can use the if inside an assignment, which seems like a very clean way to solve it to me:
converted_data = {
raw_item['name']: {
'state': raw_item['field_a'],
'variants': [] if 'variants' not in raw_item['field_b'] else
[str(variant) for variant in raw_item['field_b']['variants']]
} for raw_item in example
}
(Note: using str() instead of undefined function that was given in initial example)
After clarification of the question, here's an alternate solution that adds a different dictionary (missing the empty 'variations' key if there is none:
converted_data = {
raw_item['name']: {
'state': raw_item['field_a'],
'variants': [str(variant) for variant in raw_item['field_b']['variants']]
} if 'variants' in raw_item['field_b'] else {
'state': raw_item['field_a'],
} for raw_item in example
}
If the question actually is: can a key/value pair in a dictionary literal be optional (which would solve your problem) then the answer is simply "no". But the above achieves the same for this simple example.
If the real life situation is more complicated, simply construct the dictionary as in the first solution given here and then use del(dictionary['key']) to remove any added keys that have a None or [] value after construction.
For example, after the first example, converted_data could be cleaned up with:
for item in converted_data.values:
if not item['variants']:
del(item['variants'])
You could pass the process out to a function?
def check_age(age):
return age >= 18
my_dic = {
"age": 25,
"allowed_to_drink": check_age(25)
}
You end up with the value as the result of the function call
{'age': 25, 'allowed_to_drink': True}
How you would implement this I don't know, but some food for thought.

Python - Searching JSON

I have JSON output as follows:
{
"service": [{
"name": ["Production"],
"id": ["256212"]
}, {
"name": ["Non-Production"],
"id": ["256213"]
}]
}
I wish to find all ID's where the pair contains "Non-Production" as a name.
I was thinking along the lines of running a loop to check, something like this:
data = json.load(urllib2.urlopen(URL))
for key, value in data.iteritems():
if "Non-Production" in key[value]: print key[value]
However, I can't seem to get the name and ID from the "service" tree, it returns:
if "Non-Production" in key[value]: print key[value]
TypeError: string indices must be integers
Assumptions:
The JSON is in a fixed format, this can't be changed
I do not have root access, and unable to install any additional packages
Essentially the goal is to obtain a list of ID's of non production "services" in the most optimal way.
Here you go:
data = {
"service": [
{"name": ["Production"],
"id": ["256212"]
},
{"name": ["Non-Production"],
"id": ["256213"]}
]
}
for item in data["service"]:
if "Non-Production" in item["name"]:
print(item["id"])
Whatever I see JSON I think about functionnal programming ! Anyone else ?!
I think it is a better idea if you use function like concat or flat, filter and reduce, etc.
Egg one liner:
[s.get('id', [0])[0] for s in filter(lambda srv : "Non-Production" not in srv.get('name', []), data.get('service', {}))]
EDIT:
I updated the code, even if data = {}, the result will be [] an empty id list.

How to add a key,value pair to a list?

I would like to be able to create a list of key, list pairs ( I think that's the most accurate way to describe my desired solution...)
I have a list of dictionaries and would like to add an element to each of these dictionaries that is a list of dictionaries (a mouthful, I know...).
To do this, I try to append key, value pairs to a list. When I do this I get a syntax error ostensibly tripped on the colon in the key:value pair.
Here's my code:
d_l[0]['abilities'] = list()
d_l[0]['abilities'].append(abilities_m_l[job_row]['Element Name']:list()) # ability: stats about ability
where d_l is a list of dictionaries, 'abilities' is a key that I am creating.
And here's my error (the caret is on the colon (although in the past it's mislabeled the location of the error)).
d_l[0]['abilities'].append(abilities_m_l[job_row]['Element Name']:list()) # ability: stats about ability
^
SyntaxError: invalid syntax
logout
If it helps, this is the desired overall structure:
{
'job':'clerk', 'description': 'works in a bank', 'abilities': [
'math': [
'imp': {
'Data Value': 4.5,
'N' : 8,
'S_E': 0.19
},
'level': {
'Data Value': 4.75,
'N': 8,
'S_E': 0.25
}
],
'english': [
'imp': {
},
'level': {
}
],
'dexterity': [
'imp':{
},
'level': {
}
]
]
},
Thanks so much! If you see obvious flaws in my arrangement just above (maybe I should be using a dictionary for abilities instead of a list?) please let me know.
You want to append a dict - note the {}, eg:
.append( {abilities_m_l[job_row]['Element Name']:list()} )
And it's more Pythonic and efficient to use [] for an empty list...

Categories